/** * Copyright 2008 - 2012 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.3.3 */ package org.test; import loon.action.ActionBind; import loon.action.ActionListener; import loon.action.RotateTo; import loon.action.map.TileMap; import loon.action.sprite.Animation; import loon.action.sprite.JumpObject; import loon.action.sprite.SpriteBatch; import loon.action.sprite.ActionObject; import loon.action.sprite.SpriteBatchScreen; import loon.canvas.LColor; import loon.component.LPad; import loon.event.ActionKey; import loon.event.GameKey; import loon.event.GameTouch; import loon.event.SysKey; import loon.geom.Vector2f; //PS:使用SpriteBatch时,请尽可能使用同一LTexture衍生出的图片,这样后台能有效的合并处理 public class GameMapTest extends SpriteBatchScreen { // 敌人用类 class Enemy extends ActionObject { private static final float SPEED = 1; protected float vx; protected float vy; public Enemy(float x, float y, Animation animation, TileMap tiles) { super(x, y, 32, 32, animation, tiles); vx = -SPEED; vy = 0; } public void update(long e) { float x = getX(); float y = getY(); vy += 0.6f; float newX = x + vx; // 判断预期坐标是否与瓦片相撞(X坐标测试) Vector2f tile = tiles.getTileCollision(this, newX, y); if (tile == null) { x = newX; } else { if (vx > 0) { x = tiles.tilesToPixelsX(tile.x) - getWidth(); } else if (vx < 0) { x = tiles.tilesToPixelsY(tile.x + 1); } vx = -vx; } float newY = y + vy; // 判断预期坐标是否与瓦片相撞(y坐标测试) tile = tiles.getTileCollision(this, x, newY); if (tile == null) { y = newY; } else { if (vy > 0) { y = tiles.tilesToPixelsY(tile.y) - getHeight(); vy = 0; } else if (vy < 0) { y = tiles.tilesToPixelsY(tile.y + 1); vy = 0; } } animation.update(elapsedTime); // 注入新坐标 setLocation(x, y); } } // 二次跳跃用类(物品) class JumperTwo extends ActionObject { public JumperTwo(float x, float y, Animation animation, TileMap tiles) { super(x, y, 32, 32, animation, tiles); } public void use(JumpObject hero) { hero.setJumperTwo(true); } public void update(long elapsedTime) { animation.update(elapsedTime); } } // 加速用类(物品) class Accelerator extends ActionObject { public Accelerator(float x, float y, Animation animation, TileMap tiles) { super(x, y, 32, 32, animation, tiles); } public void use(JumpObject hero) { hero.setSpeed(hero.getSpeed() * 2); } public void update(long elapsedTime) { animation.update(elapsedTime); } } // 金币用类(物品) class Coin extends ActionObject { public Coin(float x, float y, Animation animation, TileMap tiles) { super(x, y, 32, 32, animation, tiles); } public void update(long elapsedTime) { animation.update(elapsedTime); } } private JumpObject hero; // PS:如果具体游戏开发时用到多动画切换,则建议使用AnimationStorage这个Animation的子类 // 金币用动画图 private Animation coinAnimation; // 敌人用动画图(过滤掉黑色) private Animation enemyAnimation; // 加速道具动画图 private Animation accelAnimation; // 二级跳动画图 private Animation jumpertwoAnimation; public void create() { add(MultiScreenTest.getBackButton(this, 0)); // 以指定图片创建动画 this.coinAnimation = Animation.getDefaultAnimation("assets/coin.png", 32, 32, 200); this.enemyAnimation = Animation.getDefaultAnimation("assets/enemy.gif", 32, 32, 200, LColor.black); this.accelAnimation = Animation.getDefaultAnimation( "assets/accelerator.gif", 32, 32, 200); this.jumpertwoAnimation = Animation.getDefaultAnimation( "assets/jumper_two.gif", 32, 32, 200); // 注销Screen时释放下列资源 putReleases(coinAnimation, enemyAnimation, accelAnimation, jumpertwoAnimation, hero); // 加载一张由字符串形成的地图(如果不使用此方式加载,则默认使用标准的数组地图) final TileMap indexMap = TileMap.loadCharsMap("assets/map.chr", 32, 32); // 如果有配置好的LTexturePack文件,可于此注入 // indexMap.setImagePack(file); // 设定无法穿越的区域(如果不设置此项,所有索引不等于"-1"的区域都可以穿越) indexMap.setLimit(new int[] { 'B', 'C', 'i', 'c' }); indexMap.putTile('B', "assets/block.png"); int imgId = indexMap.putTile('C', "assets/coin_block.gif"); // 因为两块瓦片对应同一地图字符,所以此处使用了已载入的图片索引 indexMap.putTile('i', imgId); indexMap.putTile('c', "assets/coin_block2.gif"); // 加载此地图到窗体中 putTileMap(indexMap); // 获得地图对应的二维数组 final int[][] maps = indexMap.getMap(); int w = indexMap.getRow(); int h = indexMap.getCol(); // 遍历二维数组地图,并以此为基础添加角色到窗体之上 for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { switch (maps[j][i]) { case 'o': Coin coin = new Coin(indexMap.tilesToPixelsX(i), indexMap.tilesToPixelsY(j), new Animation( coinAnimation), indexMap); addTileObject(coin); break; case 'k': Enemy enemy = new Enemy(indexMap.tilesToPixelsX(i), indexMap.tilesToPixelsY(j), new Animation( enemyAnimation), indexMap); addTileObject(enemy); break; case 'a': Accelerator accelerator = new Accelerator( indexMap.tilesToPixelsX(i), indexMap.tilesToPixelsY(j), new Animation( accelAnimation), indexMap); addTileObject(accelerator); break; case 'j': JumperTwo jump = new JumperTwo(indexMap.tilesToPixelsX(i), indexMap.tilesToPixelsY(j), new Animation( jumpertwoAnimation), indexMap); addTileObject(jump); break; } } } // 获得主角动作图 Animation animation = Animation.getDefaultAnimation("assets/hero.png", 20, 20, 150, LColor.black); // 在像素坐标位置(192,32)放置角色,大小为32x32,动画为针对hero.png的分解图 hero = addJumpObject(192, 32, 32, 32, animation); // 让地图跟随指定对象产生移动(无论插入有多少张数组地图,此跟随默认对所有地图生效) // 另外请注意,此处能产生跟随的对像是任意LObject,并不局限于游戏角色。 follow(hero); // 监听跳跃事件 hero.listener = new JumpObject.JumpListener() { public void update(long elapsedTime) { } // 检查角色与地图中瓦片的碰撞 public void check(int x, int y) { if (indexMap.getTileID(x, y) == 'C') { indexMap.setTileID(x, y, 'c'); Enemy enemy = new Enemy(indexMap.tilesToPixelsX(x), indexMap.tilesToPixelsY(y - 1), new Animation( enemyAnimation), indexMap); add(enemy); // 标注地图已脏,强制缓存刷新 indexMap.setDirty(true); } else if (indexMap.getTileID(x + 1, y) == 'C') { indexMap.setTileID(x + 1, y, 'c'); indexMap.setDirty(true); } } }; // 对应向左行走的键盘事件 ActionKey goLeftKey = new ActionKey() { public void act(long e) { hero.setMirror(true); hero.accelerateLeft(); } }; addActionKey(SysKey.LEFT, goLeftKey); // 对应向右行走的键盘事件 ActionKey goRightKey = new ActionKey() { public void act(long e) { hero.setMirror(false); hero.accelerateRight(); } }; addActionKey(SysKey.RIGHT, goRightKey); // 对应跳跃的键盘事件(DETECT_INITIAL_PRESS_ONLY表示在放开之前,此按键不会再次触发) ActionKey jumpKey = new ActionKey(ActionKey.DETECT_INITIAL_PRESS_ONLY) { public void act(long e) { hero.jump(); } }; addActionKey(SysKey.UP, jumpKey); LPad pad = new LPad(10, 180); LPad.ClickListener click = new LPad.ClickListener() { public void up() { pressActionKey(SysKey.UP); } public void right() { pressActionKey(SysKey.RIGHT); } public void left() { pressActionKey(SysKey.LEFT); } public void down() { pressActionKey(SysKey.DOWN); } public void other() { releaseActionKeys(); } }; pad.setListener(click); add(pad); // 地图中角色事件监听(每帧都会触发一次此监听) this.updateListener = new UpdateListener() { public void act(ActionObject sprite, long elapsedTime) { // 如果主角与地图上其它对象发生碰撞(以下分别验证) if (hero.isCollision(sprite)) { // 与敌人 if (sprite instanceof Enemy) { Enemy e = (Enemy) sprite; if (hero.y() < e.y()) { hero.setForceJump(true); hero.jump(); removeTileObject(e); } else { damage(); } // 与金币 } else if (sprite instanceof Coin) { Coin coin = (Coin) sprite; removeTileObject(coin); // 与加速道具 } else if (sprite instanceof Accelerator) { removeTileObject(sprite); Accelerator accelerator = (Accelerator) sprite; accelerator.use(hero); // 与二次弹跳道具 } else if (sprite instanceof JumperTwo) { removeTileObject(sprite); JumperTwo jumperTwo = (JumperTwo) sprite; jumperTwo.use(hero); } } } }; selfAction().shakeTo(3f, 3f).start(); } private RotateTo rotate; public void damage() { // 主角与敌人碰撞时(而非踩到了敌人),触发一个旋转动作(其实效果可以做的更有趣一些, // 比如先反弹到某一方向(FireTo),然后再弹回等等,此处仅仅举个例子) if (rotate == null) { // 旋转360度,每帧累加5度 rotate = new RotateTo(360f, 5f); rotate.setActionListener(new ActionListener() { public void stop(ActionBind o) { hero.setFilterColor(LColor.white); hero.setRotation(0); } public void start(ActionBind o) { hero.setFilterColor(LColor.red); hero.jump(); } public void process(ActionBind o) { } }); addAction(rotate, hero); } else if (rotate.isComplete()) { hero.setFilterColor(LColor.red); // 直接重置rotate对象 rotate.start(hero); // 重新插入(LGame的方针是Action事件触发且结束后,自动删除该事件,所以需要重新插入) addAction(rotate, hero); } } // 背景绘制 public void after(SpriteBatch batch) { } // 前景绘制 public void before(SpriteBatch batch) { } public void update(long elapsedTime) { if (hero != null) { hero.stop(); } } // 释放资源 public void close() { } @Override public void touchDrag(GameTouch e) { } public void touchDown(GameTouch e) { } public void touchUp(GameTouch e) { } public void touchMove(GameTouch e) { } public void press(GameKey e) { } public void release(GameKey e) { } @Override public void onResume() { // TODO Auto-generated method stub } @Override public void onPause() { // TODO Auto-generated method stub } @Override public void dispose() { // TODO Auto-generated method stub } @Override public void resize(int width, int height) { // TODO Auto-generated method stub } }