超级马里奥游戏开发二(键盘监听问题)

超级玛丽键盘监听改进

在上一篇文章中的项目存在一个细节问题:

  • 长按→,然后按下↑后松开,此时→没有松开但是→检测不到pressed了。
  • 键盘监听事件是单线程的,无法识别两个按键同时按下的监听事件。
  • 当第一次按下→的时候,pressed方法里→被检测到,再按下↑的时候,pressed方法里↑被检测到,↑松开后虽然→没有松开,但是pressed方法只能检测到↑或其他新按下的键,没有松开的→不能被检测到。
  • 当→松开时released可以检测到。

为了解决这个问题,可以利用还可以检测到的released方法。这里经宇哥提点后准备将移动的方法进行修改:

  • 向左、向右等方法里面只需要改变对应的x方向的速度
  • 在线程里面不断根据x方向的速度移动物体(move方法)
  • 针对上面的问题,当→按下的时候x方向的速度为一个正整数dx,当↑按下的时候调用jump方法,将进行y方向的向上和向下的运动(在这个过程中x方向的运动在线程中完成,不会受到影响),当↑松开,角色落地后x方向的速度没有改变,会继续运动,当→松开后在released方法里面设置x方向的速度为0,角色停止移动

相应的改动:

	/*
	 * 在线程里面移动角色
	 * */
	public void run(){
		while(true){
			posx += dx;
			if(posx<0)
				posx=0;
			if(posx>screenWidth-50)
				posx = screenWidth-50;
			switchN--;
			if(switchN==0){
				index = (index+1)%4;
				switchN = 5;
			}
			try {
				Thread.sleep(15);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	
	/*
	 * 水平左行走
	 * */
	public  void moveL( ){
		if(overHead==0&&posx>0){
			images = StaticValue.marioImgsLeft;
			dx = -step;
			isMoving = 2;
		}
	}
	
	
	/*
	 * 水平右行走
	 * */
	public  void moveR( ){
		if(overHead==0&&posx<screenWidth-50){
			images = StaticValue.marioImgsRight;
			dx = step;
			isMoving = 1;
		}
	}
	
	
	
	/*
	 * 跳跃
	 * */
	public  void jump(){
		if(overHead==0&&alowJump){//是否在移动过程中跳跃,是否是再次按下jump键
			alowJump = false;
			if (isMoving == 1 ) {overHead = 1;}
			else if(isMoving == 2 ){overHead = 2;}
			//向上
			for(int i=0 ;i<jumpN;i++){
				try {
					posy -=2*step;
					dy = -2*step;
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			//向下
			for(int i=0 ;i<jumpN;i++){
				try {
					posy +=2*step;
					dy = 2*step;
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			dy = 0;
			overHead = 0;
		}
	}
	
	

(这里对跳跃还做了一个小小的处理,使得一次↑对应一个Jump动作,也就是用一个状态变量记录是否上一次的↑已经release)

处理后的全部代码:

package Mario_7_12;

import java.awt.image.BufferedImage;
import java.util.List;
/**
* FileName: Mario.java
* 游戏角色马里奥
*
* @author XuLiushen
* @Date   2020.7.19
* @version 1.00
*/
public class Mario implements Runnable  {
	private int screenWidth,screenHeight;//窗口的宽度和高度
	public  volatile  int posx,posy,dx,dy;//马里奥的位置,x,y方向的速度
	public boolean alowJump;
	public  int step,switchN;//速度
	public  int jumpN;//跳跃切换次数
	public  int index;//第index张图片
	public  List<BufferedImage> images;//马里奥动画图片的集合
	public  int isMoving;//是否在移动0没有移动,1向右,2向左
	public  int overHead;//是否在空中
	
	
	/*
	 * 在线程里面移动角色
	 * */
	public void run(){
		while(true){
			posx += dx;
			if(posx<0)
				posx=0;
			if(posx>screenWidth-50)
				posx = screenWidth-50;
			switchN--;
			if(switchN==0){
				index = (index+1)%4;
				switchN = 5;
			}
			try {
				Thread.sleep(15);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	

	/*
	 * 初始化马里奥
	 * */
	public  void init(int screenWidth,int screenHeight){
		this.screenWidth = screenWidth;
		this.screenHeight = screenHeight;
		images = StaticValue.marioImgsRight;
		step = 5;
		jumpN = 20;
		isMoving = 0;
		overHead = 0;
		posx = 0;
		posy = 400;
		index = 0;
		switchN = 5;
		dx = dy = 0;
		alowJump = true;
		Thread tr = new Thread(this);
		tr.start();
	}
	/*
	 * 水平左行走
	 * */
	public  void moveL( ){
		if(overHead==0&&posx>0){
			images = StaticValue.marioImgsLeft;
			dx = -step;
			isMoving = 2;
		}
	}
	
	
	/*
	 * 水平右行走
	 * */
	public  void moveR( ){
		if(overHead==0&&posx<screenWidth-50){
			images = StaticValue.marioImgsRight;
			dx = step;
			isMoving = 1;
		}
	}
	
	
	
	/*
	 * 跳跃
	 * */
	public  void jump(){
		if(overHead==0&&alowJump){//是否在移动过程中跳跃,是否是再次按下jump键
			alowJump = false;
			if (isMoving == 1 ) {overHead = 1;}
			else if(isMoving == 2 ){overHead = 2;}
			//向上
			for(int i=0 ;i<jumpN;i++){
				try {
					posy -=2*step;
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			//向下
			for(int i=0 ;i<jumpN;i++){
				try {
					posy +=2*step;
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			overHead = 0;
		}
	}
	
	/*
	 * 得到图片
	 * */
	public  BufferedImage getImage(){
		if(overHead !=0){
			if(overHead == 1)
				return StaticValue.marioImgsJump.get(0);
			else if(overHead == 2)
				return StaticValue.marioImgsJump.get(1);
		}
		if(isMoving == 0){
			return images.get(0);
		}
		return images.get(index);
	}
	
}

 

package Mario_7_12;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;

/**
* FileName: MFrame.java
* 界面类
*
* @author XuLiushen
* @Date   2020.7.17
* @version 1.00
*/
public class MFrame extends JFrame implements Runnable,MouseListener,KeyListener{


	private static final long serialVersionUID = 1L;
	private Thread marioThread ;//线程
	private Graphics g;
	// 创建双缓冲画布 
	private BufferedImage buffimg;
	// 取到缓冲画笔  画笔画的内容就先画在这张图片上buffimg
	private Graphics buffg;
	private Mario mario;
	
	public static void main(String[]args){
		MFrame mf = new MFrame();
		mf.startGame();//开始游戏
	}
	
	public MFrame(){
		this.setTitle("My super Mario");//标题
		this.setSize(900,600);//窗口大小
		this.setLocationRelativeTo(null);//窗口位置:正中间
		this.setResizable(false);//窗口大小不可变
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点击右上角X后结束程序
		this.setVisible(true);//窗体可见
		StaticValue.init();//初始化常量类
	    mario = new Mario();
		mario.init(this.getWidth(), this.getHeight());//初始化马里奥类
		g = this.getGraphics();//得到画布
		buffimg = new BufferedImage(getWidth(), getHeight(),BufferedImage.TYPE_INT_ARGB);//缓冲图片
		buffg = buffimg.getGraphics();//缓冲图片的画笔
		marioThread = new Thread(this);
	}
	
	/*
	 * 重写paint方法
	 * */
	public void paint(){
		super.repaint();
		g.drawImage(buffimg,0,0, null);
	}
	
	
	/*
	 * 在线程里面绘制图片
	 * */
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Image bgimg = new ImageIcon(StaticValue.bgImg1).getImage();//背景图片
			buffg.drawImage(bgimg, 0,0, null);
			buffg.drawImage(mario.getImage(), mario.posx, mario.posy, 50, 100, null);
			g.drawImage(buffimg, 0, 0, null);
		}
	}
	
	public void startGame(){
		//显示游戏进入界面背景图片
		Image bgimg = new ImageIcon(StaticValue.startImg).getImage();
		buffg.fillRect(0, 0, this.getWidth(), this.getHeight());
		buffg.drawImage(bgimg,0,0,null,null);
		g.drawImage(buffimg, 0, 0, null, null);
		//游戏开始按钮
		this.setLayout(new BorderLayout(500,500));
		JButton start_btn = new JButton();
		start_btn.setText("START");
		start_btn.setPreferredSize(new Dimension(100,50));
		start_btn.setBackground(new Color(241,77,13));
		start_btn.setBorderPainted(true);	
		start_btn.addMouseListener(this);//添加按钮监听器
		this.addKeyListener(this);//添加键盘监听器
		this.getContentPane().add("South",start_btn);
		this.setVisible(true);
	}
	
	public void inGame(){
		this.getContentPane().removeAll();//清除原来的组件
		marioThread.start();
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		inGame();//按钮按下进入游戏界面
	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}

	/*
	 * 按钮按下控制马里奥的移动
	 * */
	@Override
	public void keyPressed(KeyEvent e) {
		// TODO Auto-generated method stub
		
		int code = e.getKeyCode();
		System.out.println("pressed"+code);
		switch(code){
		case 37://向左
			mario.moveL();break;
		case 38://跳跃
			mario.jump();break;
		case 39: //向右
			mario.moveR();break;
//		case 32://攻击
		}
		
		
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
		int code = e.getKeyCode();
		if(code == 37||code == 39){
			mario.dx = 0;
			mario.isMoving = 0;//放开鼠标停了下来
			mario.index = 0;
		}
		else if(code == 38){
			mario.alowJump = true;
		}
	}


}
package Mario_7_12;


import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

/**
* FileName: StaticValue.java
* 游戏素材类
*
* @author XuLiushen
* @Date   2020.7.18
* @version 1.00
*/

public class StaticValue {

	
	public static String imgPath = System.getProperty("user.dir")+"/image/";

	public static BufferedImage startImg = null;//开始图片
	public static BufferedImage endImg = null;//结束图片
	public static BufferedImage bgImg1 = null;//背景图片1
	public static BufferedImage bgImg2 = null;//背景图片2
	public static List<BufferedImage> marioImgsRight = new ArrayList<BufferedImage> ();//马里奥向右
	public static List<BufferedImage> marioImgsLeft = new ArrayList<BufferedImage> ();//马里奥向左
	public static List<BufferedImage> marioImgsJump = new ArrayList<BufferedImage> ();//马里奥跳跃
	public static BufferedImage marioImgsDead = null;//马里奥死亡
	public static List<BufferedImage> flowerImgs = new ArrayList<BufferedImage> ();//食人花
	public static List<BufferedImage> mushroomImgs = new ArrayList<BufferedImage> ();//蘑菇怪
	public static List<BufferedImage> turtleImgs = new ArrayList<BufferedImage> ();//乌龟怪
	public static List<BufferedImage> constructionsImgs = new ArrayList<BufferedImage> ();//障碍物
	
	public static void init(){
		try {
			startImg = ImageIO.read(new File(imgPath+"bg/start.PNG"));
			endImg = ImageIO.read(new File(imgPath+"bg/background.PNG"));
			bgImg1 = ImageIO.read(new File(imgPath+"bg/firststage.gif"));
			bgImg2 = ImageIO.read(new File(imgPath+"bg/firststageend.gif"));
			
			for(int i=1;i<=4;i++){
				BufferedImage img =  ImageIO.read(new File(imgPath+"mario/"+i+".PNG"));
				marioImgsRight.add(img);
			}
		
			for(int i=6;i<=9;i++){
				BufferedImage img =  ImageIO.read(new File(imgPath+"mario/"+i+".PNG"));
				marioImgsLeft.add(img);
			}
			
			marioImgsJump.add(ImageIO.read(new File(imgPath+"mario/5.PNG")));
			marioImgsJump.add(ImageIO.read(new File(imgPath+"mario/10.PNG")));
			
			marioImgsDead = ImageIO.read(new File(imgPath+"mario/11.PNG"));
			
			for(int i=0;i<4;i++){
				BufferedImage img =  ImageIO.read(new File(imgPath+"mushroom/en1_"+i+".PNG"));
				mushroomImgs.add(img);
			}
			
			for(int i=1;i<=2;i++){
				BufferedImage img =  ImageIO.read(new File(imgPath+"flower/flower"+i+".gif"));
				turtleImgs.add(img);
			}
			
			for(int i=0;i<4;i++){
				BufferedImage img =  ImageIO.read(new File(imgPath+"turtle/en0_"+i+".PNG"));
				flowerImgs.add(img);
			}
			
			for(int i=1;i<=12;i++){
				BufferedImage img =  ImageIO.read(new File(imgPath+"construction/ob"+i+".PNG"));
				constructionsImgs.add(img);
			}
			
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
				
		
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hnu哈哈

请接受直女的么么哒????

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值