久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

学不动了,尝试用Android Jetpack Compose重写微信经典飞机大战游戏

發布時間:2023/12/14 Android 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学不动了,尝试用Android Jetpack Compose重写微信经典飞机大战游戏 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前段時間看了TechMerger大佬寫的《一氣呵成:用Compose完美復刻Flappy Bird!》,甚是有趣,按耐不住那躁動的心,筆者決定跟隨大佬的腳步通過寫游戲的方式學習Jetpack Compose,Let’s Go!
?

在這里也強推下fundroid大佬的《用Jetpack Compose做一個俄羅斯方塊游戲機》《100 行寫一個 Compose 版華容道》,十分精彩。
?

多看看大佬們的博文,受益匪淺,感謝分享。
?

《經典飛機大戰》是騰訊交流軟件微信5.0版本在2013年8月推出的軟件內置經典小游戲,現在已經找不到了,但是有其它復刻的小游戲作為參照,本文主要介紹Jetpack Compose Api的一些使用方法,供大家參考。
?

1.游戲預覽

玩家點擊并移動自己的飛機,在躲避迎面而來的其它敵機時,飛機通過發射子彈打掉其它敵機來贏取分數。一旦撞上其它敵機,游戲就結束。感興趣的小伙伴,微信小程序搜索飛機大戰就可以直接玩。
?

或者Github下載源碼導入安裝體驗:https://github.com/xiangang/AndroidDevelopmentPractices/tree/master/ComposePlane

2.游戲拆解

游戲主要由以下元素組成:
舞臺背景,玩家飛機,子彈,音效(子彈射擊音效,爆炸音效),敵機(小、中、大三種類型),動畫(玩家飛機出場動畫和爆炸動畫,敵機爆炸),道具獎勵,分數,游戲控制(開始,暫停,恢復,重開,退出)等。

2.1舞臺背景

這個簡單,畫一張圖就完事了,背景不需要運動。

2.2玩家飛機

玩家飛機,可以手指任意拖拽移動,發射子彈,并且有飛行動畫,被敵機碰撞后會爆炸,每擊落一個敵機即可獲取對應份數,游戲過程中可通過碰撞獲取子彈和爆炸道具獎勵。
?

## 2.3子彈 子彈從玩家飛機頭部處不斷出現,沿Y軸負方向以一定的速度移動,但不能沿著X軸水平移動,擊中敵機后會消耗敵機的生命值,同時子彈消失。

子彈分紅色單發子彈和藍色雙發子彈兩種類型,擊打敵機的能力(每次敵機消耗的敵機生命值)不同,大小也不同(影響碰撞檢測)。

?

2.4 敵機

敵機隨機在屏幕上方出生,沿著Y軸正方向向下運動,但不能沿著X軸水平移動,也不會發射子彈。敵機分偵察機(小)、戰斗機(中)、戰艦(大)三種類型,飛行速度,抗擊大能力各不相同。目前設計了三個難度,隨著難度的升級,敵機的數量也會不斷增多。

2.5爆炸動畫

玩家飛機被敵機碰撞,敵機被子彈擊落會觸發爆炸動畫。




2.5道具獎勵

游戲過程中,隨著游戲難度的增加,會隨機生成道具獎勵,提高玩家飛機的生存能力。道具獎勵只有兩種:子彈和炸彈。
?

2.6其它

游戲開始界面,顯示Logo,玩家飛機,開始游戲按鈕。

游戲中界面,左上角可暫停繼續游戲,右上角顯示分數,左下角顯示炸彈道具,點擊可引爆屏幕內所有敵機。

游戲結束界面,顯示分數,重新開始和退出游戲按鈕。

所有素材預覽:

游戲素材來自于:
?https://github.com/iSpring/GamePlane/
https://github.com/zhangphil/Android-WeiXinDaFeiJi

3.游戲基礎與架構

3.1基礎概念

為了使本文更易于理解,會額外補充一些說明,不感興趣建議跳過。
?

既然是做游戲開發,還是得先學習下游戲開發的基本概念,建議閱讀《游戲開發基本概念》。Sprites是個用于角色、道具、炮彈以及其他2D游戲元素的二維圖形對象。在2D游戲中,圖像部分主要是圖片的處理,圖片通常稱為精靈(Sprite)
?

精靈(Sprite) 對象需要可以被控制,可以在屏幕上移動,看下圖的Android屏幕坐標系:

關于Android屏幕坐標系更多知識點,可以參考AWeiLoveAndroid的《Android應用坐標系統全面詳解》

說白了,要使精靈(Sprite) 對象移動起來,就是要感知時間流逝,控制其坐標(x、y)發生變化。既然是對象,那就需要一個精靈(Sprite) 類。

/*** 精靈基類*/ @InternalCoroutinesApi open class Sprite(open var id: Long = System.currentTimeMillis(), //idopen var name: String = "精靈之父", //名稱open var type: Int = 0, //類型@DrawableRes open val drawableIds: List<Int> = listOf(R.drawable.sprite_player_plane_1,R.drawable.sprite_player_plane_2),//資源圖標@DrawableRes open val bombDrawableId: Int = R.drawable.sprite_explosion_seq, //敵機爆炸幀動畫資源open var segment: Int = 14, //爆炸效果由segment個片段組成:玩家飛機是4,小飛機是3,中飛機是4大飛機是6,explosion是14open var x: Int = 0, //實時x軸坐標open var y: Int = 0, //實時y軸坐標open var startX: Int = -100, //出現的起始位置open var startY: Int = -100, //出現的起始位置open var width: Dp = BULLET_SPRITE_WIDTH.dp, //寬open var height: Dp = BULLET_SPRITE_HEIGHT.dp, //高open var speed: Int = 500, //飛行速度(棄用)open var velocity: Int = 40, //飛行速度(每幀移動的像素)open var state: SpriteState = SpriteState.LIFE, //控制是否顯示open var init: Boolean = false, //是否初始化,主要用于精靈初始化起點x,y坐標等,這里為什么不用state控制?state用于否顯示,init用于重新初始化數據,而且必須是精靈離開屏幕后(走完整個移動的周期)才能重新初始化,否則精靈死亡后的復用時機不好掌握(當然不一定要這么做)。 ) {fun isAlive() = state == SpriteState.LIFEfun isDead() = state == SpriteState.DEATHopen fun reBirth() {state = SpriteState.LIFE}open fun die() {state = SpriteState.DEATH}override fun toString(): String {return "Sprite(id=$id, name='$name', drawableIds=$drawableIds, bombDrawableId=$bombDrawableId, segment=$segment, x=$x, y=$y, width=$width, height=$height, speed=$speed, state=$state)"}}

有了精靈(Sprite) 類,面向對象編程,我們只要控制精靈(Sprite) 對象的x、y屬性即可控制**精靈(Sprite)**對象產生位移。
?

閱讀到此,需要具備Jetpack Compose的基礎,建議閱讀官方文檔《Compose 編程思想》,結合fundroid大佬的Jetpack Compose系列教程更佳。
?

在Jetpack Compose UI體系中,通過Modifier.offset { IntOffset(x, y) }傳參給可組合函數的方式,實現View在Android屏幕坐標系上的相對于原點(0,0)的偏移量。
?

關于Modifier的介紹,見官方文檔《Modifier》
關于Modifier的使用,見官方文檔《Compose 修飾符列表》

?

除了控制精靈(Sprite) 對象的x、y屬性,前面還提到了,要感知時間的流逝。
?

那怎么感知?大佬們的做法是通過LaunchedEffect啟動一個定時任務,定期發送一個更新視圖的動作AutoTick。
?

當 LaunchedEffect 進入組合時,它會啟動一個協程,并將代碼塊作為參數傳遞。如果 LaunchedEffect 退出組合,協程將取消。如下代碼,通過協程死循環執行100s的延遲任務。

//繪制setContent {ComposePlaneTheme {// A surface container using the 'background' color from the themeSurface(color = MaterialTheme.colors.background) {//利用協程定時執行LaunchedEffect(key1 = Unit) {while (isActive) {delay(100)//TODO auto tick,to do something}}Stage(gameViewModel, onGameAction)}}}

這樣,就可以在組合函數中不斷的修改精靈(Sprite) 對象的x、y屬性,看起來精靈(Sprite) 對象就是在不斷運動了。

LaunchedEffect:在某個可組合項的作用域內運行掛起函數,介紹見《Compose 中的附帶效應》

?

然而,筆者一開始不是使用這種AutoTick的方式,而是純粹的使用Jetpack Compose的重復動畫(本質上跟LaunchedEffect AutoTick方式沒什么區別,最低級別的動畫 API:**TargetBasedAnimation **也是用LaunchedEffect實現的),走了一些彎路,后面轉而使用AutoTick實現發現的確很好用,不過為了展現不同的思路,于是部分邏輯又改成使用動畫來實現,但是看效果每次動畫結束重新開始的瞬間有感覺都明顯的頓挫感,這個問題暫時沒解決。
?

3.2狀態和架構

狀態:可以簡單理解為隨時間變化的任何值。
?

對于精靈(Sprite) 對象而言,我們需要更新其x、y屬性(狀態)并驅動界面中元素進行重新繪制,從而使View發生位移。
?

由于 Compose 是聲明式工具集,因此更新它的唯一方法是通過新參數調用同一可組合函數。這些參數是界面狀態的表現形式。每當狀態更新時,都會發生重組。可組合函數必須明確獲知新狀態,才能相應地進行更新。如下圖:

重新繪制界面元素,需要更新狀態并使用新數據調用可組合函數,完成重組過程。但可組合函數本質就是一個函數,那就不能夠在可組合函數里聲明局部變量來管理狀態,那應該怎么管理?

3.3.1可組合項中的狀態管理

可組合函數使用 remember存儲單個對象。系統會在初始組合期間將由 remember 計算的值存儲在組合中,并在重組期間返回存儲的值。remember 既可用于存儲可變對象,又可用于存儲不可變對象。簡單的說,使用remember 可以在可組合函數中保存和讀取狀態的最新值。
?

但使用remember 也僅能保存和讀取狀態的最新值,我們的目的是狀態發生改變時自動驅動重組。
?

使用mutableStateOf 創建可觀察的 MutableState,后者是與 Compose 運行時集成的可觀察類型,這樣一來就可以觀察狀態到狀態的變化,從而驅動可組合函數重組,進而重新繪制界面元素。
?

示例代碼如下:

@Composable fun LowComposable() {Column(modifier = Modifier.padding(16.dp)) {var name by remember { mutableStateOf("") }if (name.isNotEmpty()) {Text(text = "Hello, $name!",modifier = Modifier.padding(bottom = 8.dp),style = MaterialTheme.typography.h5)}OutlinedTextField(value = name,onValueChange = { name = it },label = { Text("Name") })} }

name 如有任何更改,系統會安排重組讀取name 的所有可組合函數。remember 和mutableStateOf 缺一不可,想一想,如果少了其中一個,現象是怎樣的?
?

Jetpack Compose 支持其他可觀察類型,如:LiveData,Flow,RxJava2等。在 Jetpack Compose 中讀取其他可觀察類型之前,必須將其轉換為 State,以便 Jetpack Compose 可以在狀態發生變化時自動重組界面,具體使用方法等下會上代碼。

以下這段很重要,筆者就踩了這個坑。

注意:在 Compose 中將可變對象(如 ArrayListmutableListOf())用作狀態會導致用戶在您的應用中看到不正確或陳舊的數據。
不可觀察的可變對象(如 ArrayList 或可變數據類)不能由 Compose 觀察,因而 Compose 不能在它們發生變化時觸發重組。
我們建議您使用可觀察的數據存儲器(如 State<List>)和不可變的 listOf(),而不是使用不可觀察的可變對象。

?

3.3.2狀態提升

上面的示例代碼,狀態是定義在可組合函數內部的。這樣的方式優點是不依賴于外部,可獨立使用。缺點是外部無法更改這個可組合函數內部的狀態,難以跟其它可組合函數聯動,這樣一來,復用性就降低了。好的架構,應該是高復用的。那有什么辦法可以解決這個問題?
?

使用狀態提升。既然可組合函數內部的狀態,不能被外部修改,那就把狀態從內部移到外部即可。Jetpack Compose 中的常規狀態提升模式是將狀態變量替換為兩個參數:一個是狀態值,一個是狀態修改函數。
?

具體見官方文檔《狀態提升》

?

示例代碼:

//狀態提升前 @Composable fun LowComposable() {Column(modifier = Modifier.padding(16.dp)) {var name by remember { mutableStateOf("") }if (name.isNotEmpty()) {Text(text = "Hello, $name!",modifier = Modifier.padding(bottom = 8.dp),style = MaterialTheme.typography.h5)}OutlinedTextField(value = name,onValueChange = { name = it },label = { Text("Name") })} }//狀態提升后 //LowComposable的狀態提升到了HighComposable,再通過參數形式從HighComposable下降到LowComposable,同時,狀態的修改,也通過參數往下傳遞一個狀態值修改函數,這樣一來LowComposable可以讀取狀態值,也可以修改狀態值,但狀態的管理是HighComposable負責的。 @Composable fun HighComposable() {var name by rememberSaveable { mutableStateOf("") }LowComposable(name = name, onNameChange = { name = it }) }@Composable fun LowComposable(name: String, onNameChange: (String) -> Unit) {Column(modifier = Modifier.padding(16.dp)) {Text(text = "Hello, $name",modifier = Modifier.padding(bottom = 8.dp),style = MaterialTheme.typography.h5)OutlinedTextField(value = name,onValueChange = onNameChange,label = { Text("Name") })} }

如上圖,狀態管理從下層可組合函數提升到最低公共上層可組合函數,狀態的值和狀態更新函數從最低公共上層可組合函數傳參給下層可組合函數,下層可組合函數直接讀取狀態值,狀態更新還是由最低公共上層可組合函數來實現,下層可組合函數只負責傳參調用狀態更新函數(得益于Kotlin的語言特性,函數可以像參數一樣傳遞,因此UI交互后可以直接調用傳遞過來的函數)。
?

將函數用作參數或返回值的介紹見《高階函數與 lambda 表達式》

?

像這種狀態提升后變成狀態下降、事件上升的模式稱為“單向數據流”。通過遵循單向數據流,統一由最低公共上層可組合函數管理狀態,從而使下層可組合函數解耦,這意味著最低公共上層可組合函數的修改幾乎不影響下層可組合函數,這樣一來下層可組合函數即可高效復用。
?

這里比較啰嗦,筆者剛開始看官方文檔的時候,狀態又是提升又是下降的,很暈,這里試圖講清楚,不知道有沒有弄巧成拙。

3.3.3ViewModel狀態管理

既然是Jetpack Compose怎么能少得了ViewModel?對于位于 Compose 界面樹中較高位置的可組合項或作為 Navigation 庫中目標的可組合項,Android官方建議使用 ViewModel 作為狀態容器。
?

ViewModel 在配置更改后可以繼續保持狀態,在這里封裝與界面相關的狀態和事件是非常合適的,而且不必關心托管 Compose 代碼的 activity 或 fragment 生命周期。

前面提到Jetpack Compose 支持其他可觀察類型,如:LiveData,Flow,RxJava2等,在ViewModel這里就派上用場了。ViewModel 應在可觀察的容器(如 LiveData 或 StateFlow)中公開狀態。在組合期間讀取狀態對象時,組合的當前重組作用域會自動訂閱該狀態對象的更新。

在 Jetpack Compose 中使用 LiveData 和 ViewModel 實現單向數據流的示例使用如下所示的 ViewModel 實現:

@InternalCoroutinesApi class GameViewModel(application: Application) : AndroidViewModel(application) {/*** 分數記錄*/private val _gameScore = MutableLiveData(0)val gameScore: LiveData<Int> = _gameScorefun onGameScoreChange(score: Int) {_gameScore.value = score}}/*** 舞臺*/ @InternalCoroutinesApi @ExperimentalComposeUiApi @ExperimentalAnimationApi @Composable fun Stage(gameViewModel: GameViewModel, onGameAction: OnGameAction = OnGameAction()) {LogUtil.printLog(message = "Stage -------> ")//狀態提升到這里,介紹見官方文檔:https://developer.android.google.cn/jetpack/compose/state#state-hoisting//這里主要是方便統一管理,也避免直接使用ViewModel導致無法預覽(預覽時viewModel()會報錯)//獲取游戲分數val gameScore by gameViewModel.gameScore.observeAsState(0)val modifier = Modifier.fillMaxSize()Box(modifier = modifier.run {pointerInteropFilter {when (it.action) {MotionEvent.ACTION_DOWN -> {LogUtil.printLog(message = "Stage ACTION_DOWN ")}MotionEvent.ACTION_MOVE -> {LogUtil.printLog(message = "Stage ACTION_MOVE")return@pointerInteropFilter false}MotionEvent.ACTION_CANCEL, Stage.ACTION_UP -> {LogUtil.printLog(message = "GameScreen ACTION_CANCEL/UP")return@pointerInteropFilter false}}false}}) {//得分ComposeScore(gameScore)}}@InternalCoroutinesApi @ExperimentalComposeUiApi @ExperimentalAnimationApi @Preview() @Composable fun PreviewStage() {val gameViewModel: GameViewModel = viewModel()Stage(gameViewModel) }/*** 得分*/ @InternalCoroutinesApi @Composable fun ComposeScore(gameScore: Int = 0, ) {LogUtil.printLog(message = "ComposeScore()")Row(modifier = Modifier.fillMaxWidth().padding(10.dp).absolutePadding(top = 20.dp)) {Text(text = "score: $gameScore",modifier = Modifier.padding(start = 4.dp).align(Alignment.CenterVertically).wrapContentWidth(Alignment.End),style = MaterialTheme.typography.h5,color = Color.Black,fontFamily = ScoreFontFamily)} }@InternalCoroutinesApi @Preview() @Composable fun PreviewComposeScore() {ComposeScore() }class MainActivity : ComponentActivity() {@InternalCoroutinesApiprivate val gameViewModel: GameViewModel by viewModels()@InternalCoroutinesApi@ExperimentalComposeUiApi@ExperimentalAnimationApioverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposePlaneTheme {// A surface container using the 'background' color from the themeSurface(color = MaterialTheme.colors.background) {//利用協程定時執行任務LaunchedEffect(key1 = Unit) {while (isActive) {delay(100)var score = gameViewModel.gameScore.valuegameViewModel.onGameScoreChange(++score)}}Stage(gameViewModel, onGameAction)}}}} }@InternalCoroutinesApi @ExperimentalComposeUiApi @ExperimentalAnimationApi @Preview() @Composable fun PreviewStage() {val gameViewModel: GameViewModel = viewModel()Stage(gameViewModel) }

可以看到,狀態管理是在ViewModel進行的,遵循單向數據流,Compose只負責顯示UI。這樣一來,ViewModel和Compose可組合函數就都可以復用了。
?

3.3.4游戲架構

建議先閱讀fundroid大佬的《【Android】MVI架構快速入門:從雙向綁定到單向數據流》《Jetpack Compose 架構比較:MVP & MVVM & MVI》,筆者也是第一次聽說MVI架構。
?

有了以上鋪墊,再來講架構,就比較容易理解了,看下圖。
?


分析下這個架構:
1.定義了一個GameViewMode用于管理游戲狀態,使用MutableStateFlow作為可觀察容器,GameViewMode的對象在Activity/Fragment中生成。
?

2.定義了一個GameAction用于更新游戲狀態,包含start,pause等函數用于更新不同的狀態值,GameAction的實現在GameViewMode中。
?

3.定義了一個Compose最低公共可組合函數Stage(游戲開發術語的中的概念:舞臺),傳入GameViewMode實例,通過collectAsState把GameViewMode中公開的StateFlow轉換為 State,并將State(狀態)下降到下層可組合函數Background等,并傳遞了GameAction對象實現Event(事件)上升。
?

4.其它下層可組合函數只負責觀察State變化進行重繪和調用GameAction定義的Action函數即可。
?

5.這樣一來,一個完整的單向數據流架構就完成了。
?

注意:由于代碼還在不斷迭代中,圖中部分Compose和GameAction的函數可能未完整列出或名稱上有所改動,實際以源碼為準)

?

所有的精靈類如下:

3.3.5部分核心代碼

游戲狀態和動作定義:

/*** 游戲狀態*/ enum class GameState {Waiting, // wait to startRunning, // gamingPaused, // pauseDying, // hit enemy and dyingOver, // overExit // finish activity }/*** 游戲動作*/ @InternalCoroutinesApi data class GameAction(val start: () -> Unit = {}, //游戲狀態進入Running,游戲中val pause: () -> Unit = {},//游戲狀態進入Paused,暫停val reset: () -> Unit = {},//游戲狀態進入Waiting,顯示GameWaitingval die: () -> Unit = {},//游戲狀態進入Dying,觸發爆炸動畫val over: () -> Unit = {},//游戲狀態進入Over,顯示GameOverBoardval exit: () -> Unit = {},//退出游戲val playerMove: (x: Int, y: Int) -> Unit = { _: Int, _: Int -> },//玩家移動val score: (score: Int) -> Unit = { _: Int -> },//更新分數val award: (award: Award) -> Unit = { _: Award -> },//獲得獎勵val createBullet: () -> Unit = { },//子彈生成val initBullet: (bullet: Bullet) -> Unit = { _: Bullet -> },//子彈初始化出生位置val shooting: (resId: Int) -> Unit = { _: Int -> },//射擊val destroyAllEnemy: () -> Unit = {},//摧毀所有敵機val levelUp: (score: Int) -> Unit = { _: Int -> },//難度升級 )

?

GameViewModel中定義的StateFlow和GameAction實現代碼如下:

@InternalCoroutinesApi class GameViewModel(application: Application) : AndroidViewModel(application) {//idval id = AtomicLong(0L)/*** 游戲狀態StateFlow*/private val _gameStateFlow = MutableStateFlow(GameState.Waiting)val gameStateFlow = _gameStateFlow.asStateFlow()/*** 玩家飛機StateFlow*/private val _playerPlaneStateFlow = MutableStateFlow(PlayerPlane())val playerPlaneStateFlow = _playerPlaneStateFlow.asStateFlow()/*** 敵機StateFlow*/private val _enemyPlaneListStateFlow = MutableStateFlow(mutableListOf<EnemyPlane>())val enemyPlaneListStateFlow = _enemyPlaneListStateFlow.asStateFlow()/*** 子彈StateFlow*/private val _bulletListStateFlow = MutableStateFlow(mutableListOf<Bullet>())val bulletListStateFlow = _bulletListStateFlow.asStateFlow()/*** 道具獎勵tateFlow*/private val _awardListStateFlow = MutableStateFlow(CopyOnWriteArrayList<Award>())val awardListStateFlow = _awardListStateFlow.asStateFlow()/*** 分數記錄*/private val _gameScoreStateFlow = MutableStateFlow(0)val gameScoreStateFlow = _gameScoreStateFlow.asStateFlow()/*** 難度等級*/private val _gameLevelStateFlow = MutableStateFlow(0)//游戲動作val onGameAction = GameAction(start = {onGameStateFlowChange(GameState.Running)},reset = {resetGame()onGameStateFlowChange(GameState.Waiting)},pause = {onGameStateFlowChange(GameState.Paused)},playerMove = { x, y ->run {onPlayerPlaneMove(x, y)}},score = { score ->run {//播放爆炸音效viewModelScope.launch {withContext(Dispatchers.Default) {SoundPoolUtil.getInstance(application.applicationContext).playByRes(R.raw.explosion)//播放res中的音頻}}//更新分數onGameScoreStateFlowChange(score)//簡單處理,不同分數對應不同的等級if (score in 100..999) {onGameLevelStateFlowChange(2)}if (score in 1000..1999) {onGameLevelStateFlowChange(3)}//分數是100整數時,產生隨機獎勵if (score % 100 == 0) {createAwardSprite()}}},award = { award ->run {//獎勵子彈if (award.type == AWARD_BULLET) {val bulletAward = playerPlaneStateFlow.value.bulletAwardvar num = bulletAward and 0xFFFF //數量num += award.amountonPlayerAwardBullet(BULLET_DOUBLE shl 16 or num)}//獎勵爆炸道具if (award.type == AWARD_BOMB) {val bombAward = playerPlaneStateFlow.value.bombAwardvar num = bombAward and 0xFFFF //數量num += award.amountonPlayerAwardBomb(0 shl 16 or num)}onAwardRemove(award)}},die = {viewModelScope.launch {withContext(Dispatchers.Default) {SoundPoolUtil.getInstance(application.applicationContext).playByRes(R.raw.explosion)//播放res中的音頻}}onGameStateFlowChange(GameState.Dying)},over = {onGameStateFlowChange(GameState.Over)},exit = {onGameStateFlowChange(GameState.Exit)},destroyAllEnemy = {onDestroyAllEnemy()},shooting = { resId ->run {LogUtil.printLog(message = "onShooting resId $resId")viewModelScope.launch {withContext(Dispatchers.Default) {SoundPoolUtil.getInstance(application.applicationContext).playByRes(resId)//播放res中的音頻}}}},createBullet = { createBullet() },initBullet = { initBullet(it) },) }

Stage最低公共可組合函數:

/*** 舞臺*/ @InternalCoroutinesApi @ExperimentalComposeUiApi @ExperimentalAnimationApi @Composable fun Stage(gameViewModel: GameViewModel) {LogUtil.printLog(message = "Stage -------> ")//狀態提升到這里,介紹見官方文檔:https://developer.android.google.cn/jetpack/compose/state#state-hoisting//這里主要是方便統一管理,也避免直接使用ViewModel導致無法預覽(預覽時viewModel()會報錯)//獲取游戲狀態val gameState by gameViewModel.gameStateFlow.collectAsState()//獲取游戲分數val gameScore by gameViewModel.gameScoreStateFlow.collectAsState(0)//獲取玩家飛機val playerPlane by gameViewModel.playerPlaneStateFlow.collectAsState()//獲取所有子彈val bulletList by gameViewModel.bulletListStateFlow.collectAsState()//獲取所有獎勵val awardList by gameViewModel.awardListStateFlow.collectAsState()//獲取所有敵軍val enemyPlaneList by gameViewModel.enemyPlaneListStateFlow.collectAsState()//獲取游戲動作函數val gameAction: GameAction = gameViewModel.onGameActionval modifier = Modifier.fillMaxSize()Box(modifier = modifier) {// 遠景FarBackground(modifier)//游戲開始界面GameStart(gameState, playerPlane, gameAction)//玩家飛機PlayerPlaneSprite(gameState,playerPlane,gameAction)//玩家飛機出場飛入動畫PlayerPlaneAnimIn(gameState,playerPlane,gameAction)//玩家飛機爆炸動畫PlayerPlaneBombSprite(gameState, playerPlane, gameAction)//敵軍飛機EnemyPlaneSprite(gameState,gameScore,playerPlane,bulletList,enemyPlaneList,gameAction)//子彈BulletSprite(gameState, bulletList, gameAction)//獎勵AwardSprite(gameState, playerPlane, awardList, gameAction)//爆炸道具BombAward(playerPlane, gameAction)//游戲得分GameScore(gameState, gameScore, gameAction)//游戲開始界面GameOver(gameState, gameScore, gameAction)}}

溫馨提示:為了提高閱讀的流暢性和完整性,此章節摘抄整理大量來自于官方文檔:《狀態和 Jetpack Compose》的內容,并加入了自己的理解,可能確實太啰嗦了,并且貼了較多代碼,也不好,歡迎大家指正,提提意見。

4.玩家飛機控制和動畫

從本章節到后面的章節,幾乎都是介紹Compose設計相關知識點的用法,其中關于動畫的使用比較多,不感興趣可直接跳過,閱讀官方文檔《Compose設計》結合自身實踐更佳。

前面提到過定義了一個Sprite精靈基類,玩家飛機定義一個PlayerPlane繼承Sprite,增加獨有的屬性即可使用,代碼如下:

/*** 玩家飛機精靈*/ const val PLAYER_PLANE_SPRITE_SIZE = 60 const val PLAYER_PLANE_PROTECT = 60@InternalCoroutinesApi data class PlayerPlane(override var id: Long = System.currentTimeMillis(), //idoverride var name: String = "雷電",@DrawableRes override val drawableIds: List<Int> = listOf(R.drawable.sprite_player_plane_1,R.drawable.sprite_player_plane_2), //玩家飛機資源圖標@DrawableRes val bombDrawableIds: Int = R.drawable.sprite_player_plane_bomb_seq, //玩家飛機爆炸幀動畫資源override var segment: Int = 4, //爆炸效果由segment個片段組成override var x: Int = -100, //玩家飛機在X軸上的位置override var y: Int = -100, //玩家飛機在Y軸上的位置override var width: Dp = PLAYER_PLANE_SPRITE_SIZE.dp, //寬override var height: Dp = PLAYER_PLANE_SPRITE_SIZE.dp, //高var protect: Int = PLAYER_PLANE_PROTECT, //剛出現時的閃爍次數(此時無敵狀態)var life: Int = 1, //生命(幾條命的意思,不像敵機,可以經受多次擊打,玩家飛機碰一下就Over)var animateIn: Boolean = true, //是否需要出場動畫var bulletAward: Int = BULLET_DOUBLE shl 16 or 0, //子彈獎勵(子彈類型 | 子彈數量),類型0是單發紅色子彈,1是藍色雙發子彈var bombAward: Int = 0 shl 16 or 0, //爆炸獎勵(爆炸類型 | 爆炸數量),目前類型只有0 ) : Sprite() {/*** 減少保護次數,為0的時候碰撞即爆炸*/fun reduceProtect() {if (protect > 0) {protect--}}fun isNoProtect() = protect <= 0override fun reBirth() {state = SpriteState.LIFEanimateIn = truex = startXy = startYprotect = PLAYER_PLANE_PROTECTbulletAward = 0bombAward = 0} }

Compose代碼如下:

/*** 玩家飛機,可手指拖動,沿XY軸同時移動*/ val FastShowAndHiddenEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 1.0f, 1.0f)//噴氣速度變化 const val SMALL_ENEMY_PLANE_SPRITE_ALPHA = 100; //噴氣速度@InternalCoroutinesApi @ExperimentalAnimationApi @Composable fun PlayerPlaneSprite(gameState: GameState,playerPlane: PlayerPlane,gameAction: GameAction ) {if (!(gameState == GameState.Running || gameState == GameState.Paused)) {return}//初始化參數val widthPixels = LocalContext.current.resources.displayMetrics.widthPixelsval heightPixels = LocalContext.current.resources.displayMetrics.heightPixelsval playerPlaneHeightPx = with(LocalDensity.current) { playerPlane.height.toPx() }//循環動畫val infiniteTransition = rememberInfiniteTransition()val alpha by infiniteTransition.animateFloat(initialValue = 0f,targetValue = 1f,animationSpec = infiniteRepeatable(animation = tween(SMALL_ENEMY_PLANE_SPRITE_ALPHA, easing = FastShowAndHiddenEasing),repeatMode = RepeatMode.Restart))//游戲開始后,動畫完成減少保護次數,直到為0if (gameState == GameState.Running && !playerPlane.isNoProtect() && alpha >= 0.5f) {playerPlane.reduceProtect()}LogUtil.printLog(message = "PlayerPlaneSprite() playerPlane.x = ${playerPlane.x} playerPlane.y = ${playerPlane.y}")Box(modifier = Modifier.fillMaxSize()) {Image(painter = painterResource(id = R.drawable.sprite_player_plane_1),contentScale = ContentScale.FillBounds,contentDescription = null,modifier = Modifier.offset { IntOffset(playerPlane.x, playerPlane.y) }//.background(Color.Blue).size(playerPlane.width, playerPlane.height).pointerInput(Unit) {detectDragGestures { change, dragAmount ->change.consumeAllChanges()var newOffsetX = playerPlane.xvar newOffsetY = playerPlane.y//邊界檢測when {newOffsetX + dragAmount.x <= 0 -> {newOffsetX = 0}(newOffsetX + dragAmount.x + playerPlaneHeightPx) >= widthPixels -> {widthPixels.let {newOffsetX = it - playerPlaneHeightPx.roundToInt()}}else -> {newOffsetX += dragAmount.x.roundToInt()}}when {newOffsetY + dragAmount.y <= 0 -> {newOffsetY = 0}(newOffsetY + dragAmount.y) >= heightPixels -> {heightPixels.let {newOffsetY = it}}else -> {newOffsetY += dragAmount.y.roundToInt()}}gameAction.playerMove(newOffsetX, newOffsetY)}}.alpha(if (gameState == GameState.Running || gameState == GameState.Paused) {if (alpha < 0.5f) 0f else 1f} else {0f}))//顯示另一張飛機噴氣圖,通過循環設置相反的alpha,達到動態噴氣的效果Image(painter = painterResource(id = R.drawable.sprite_player_plane_2),contentScale = ContentScale.FillBounds,contentDescription = null,modifier = Modifier.offset { IntOffset(playerPlane.x, playerPlane.y) }//.background(Color.Blue).size(playerPlane.width, playerPlane.height).alpha(if (gameState == GameState.Running || gameState == GameState.Paused) {//如果處于保護狀態這里就不顯示了if (!playerPlane.isNoProtect()) {0f} else {if (1 - alpha < 0.5f) 0f else 1f}} else {0f}))} }

4.1拖拽控制

實現效果:

通過 pointerInput 修飾符使用拖動手勢檢測器,不斷的調用GameAction的onPlayerPlaneMove(x, y)函數更新PlayerPlane的坐標就可以了。 pointerInput 的使用見官方文檔《手勢》。
?

Compose拖拽代碼:

Modifier.pointerInput(Unit) {detectDragGestures { change, dragAmount ->change.consumeAllChanges()var newOffsetX = playerPlane.xvar newOffsetY = playerPlane.y//邊界檢測when {newOffsetX + dragAmount.x <= 0 -> {newOffsetX = 0}(newOffsetX + dragAmount.x + playerPlaneHeightPx) >= widthPixels -> {widthPixels.let {newOffsetX = it - playerPlaneHeightPx.roundToInt()}}else -> {newOffsetX += dragAmount.x.roundToInt()}}when {newOffsetY + dragAmount.y <= 0 -> {newOffsetY = 0}(newOffsetY + dragAmount.y) >= heightPixels -> {heightPixels.let {newOffsetY = it}}else -> {newOffsetY += dragAmount.y.roundToInt()}}gameAction.playerMove(newOffsetX, newOffsetY)}}

GameVIewModel更新玩家飛機坐標代碼:

/*** 玩家飛機StateFlow*/private val _playerPlaneStateFlow = MutableStateFlow(PlayerPlane())val playerPlaneStateFlow = _playerPlaneStateFlow.asStateFlow()private fun onPlayerPlaneStateFlowChange(plane: PlayerPlane) {viewModelScope.launch {withContext(Dispatchers.Default) {_playerPlaneStateFlow.emit(plane)}}}/*** 玩家飛機移動*/private fun onPlayerPlaneMove(x: Int, y: Int) {if (gameStateFlow.value != GameState.Running) {return}val playerPlane = playerPlaneStateFlow.valueplayerPlane.x = xplayerPlane.y = yif (playerPlane.animateIn) {playerPlane.animateIn = false}onPlayerPlaneStateFlowChange(playerPlane)}

4.2飛行動畫

飛行動畫通過循環顯示和隱藏兩張不同的圖片來實現,一開始還在想怎么設置Compose Image的visibility(慣性思維了),但是實際上是通過調整alpha值實現的。

實現效果:

素材圖:

關鍵代碼:

Box(modifier = Modifier.fillMaxSize()) {Image(painter = painterResource(id = R.drawable.sprite_player_plane_1),contentScale = ContentScale.FillBounds,contentDescription = null,modifier = Modifier.offset { IntOffset(playerPlane.x, playerPlane.y) }//.background(Color.Blue).size(playerPlane.width, playerPlane.height).pointerInput(Unit) {detectDragGestures { change, dragAmount ->//省略}.alpha(if (gameState == GameState.Running || gameState == GameState.Paused) {if (alpha < 0.5f) 0f else 1f} else {0f}))//顯示另一張飛機噴氣圖,通過循環設置相反的alpha,達到動態噴氣的效果Image(painter = painterResource(id = R.drawable.sprite_player_plane_2),contentScale = ContentScale.FillBounds,contentDescription = null,modifier = Modifier.offset { IntOffset(playerPlane.x, playerPlane.y) }//.background(Color.Blue).size(playerPlane.width, playerPlane.height).alpha(if (gameState == GameState.Running || gameState == GameState.Paused) {//如果處于保護狀態這里就不顯示了if (!playerPlane.isNoProtect()) {0f} else {if (1 - alpha < 0.5f) 0f else 1f}} else {0f}))}

5.子彈生成和射擊

子彈的連續射擊效果花了很多時間去調整,差強人意吧。
實現效果:

定義一個Bullet繼承Sprite,代碼如下:

/*** 子彈精靈*/ const val BULLET_SPRITE_WIDTH = 6 const val BULLET_SPRITE_HEIGHT = 18 const val BULLET_SINGLE = 0 const val BULLET_DOUBLE = 1@InternalCoroutinesApi data class Bullet(override var id: Long = System.currentTimeMillis(), //idoverride var name: String = "藍色單發子彈",override var type: Int = BULLET_SINGLE, //類型:0單發子彈,1雙發子彈@DrawableRes val drawableId: Int = R.drawable.sprite_bullet_single, //子彈資源圖標override var width: Dp = BULLET_SPRITE_WIDTH.dp, //寬override var height: Dp = BULLET_SPRITE_HEIGHT.dp, //高override var speed: Int = 200, //飛行速度,從玩家飛機頭部沿著Y軸往屏幕頂部飛行一次屏幕高度所花費的時間override var x: Int = 0, //實時x軸坐標override var y: Int = 0, //實時y軸坐標override var state: SpriteState = SpriteState.DEATH, //默認死亡override var init: Boolean = false, //默認未初始化var hit: Int = 1,//擊打能力,擊中一次敵人,敵人減掉的生命值 ) : Sprite()

上面的動畫刷新的太快了,可能看不清楚,稍微降低下子彈的飛行速度,增加背景看下效果。

注意看頂部第一顆子彈,從玩家飛機頭部出現,沿著Y軸負方向不斷的移動,后面的子彈則依次出現,一個接著一個,排列整齊,前仆后繼。看圖:

關鍵代碼:

/*** 子彈從玩家飛機頂部發射,只能沿著X軸運動,超出屏幕則銷毀,與敵機碰撞也銷毀,同時計算得分*/ @InternalCoroutinesApi @Composable fun BulletSprite(gameState: GameState = GameState.Waiting,bulletList: List<Bullet> = mutableListOf(),gameAction: GameAction = GameAction() ) {//重復動畫,1秒60幀val infiniteTransition = rememberInfiniteTransition()val frame by infiniteTransition.animateInt(initialValue = 0,targetValue = 60,animationSpec = infiniteRepeatable(animation = tween(durationMillis = 1000,easing = LinearEasing),repeatMode = RepeatMode.Restart))//游戲不在進行中if (gameState != GameState.Running) {return}//每100毫秒生成一顆子彈if (frame % 6 == 0) {gameAction.createBullet()}for (bullet in bulletList) {if (bullet.isAlive()) {//初始化起點(為什么單獨搞一個init屬性,因為init屬性是添加到隊里列時才設置false,這樣渲染時檢測init為false才去初始化起點.//如果根據isAlive來檢測會導致Bullet一死亡就算重新初始化位置,但是復用重新發射時,飛機的位置可能已經變動了。if (!bullet.init) {//初始化子彈出生位置gameAction.initBullet(bullet)//播放射擊音效,放到非UI線程gameAction.shooting(R.raw.shoot)}//子彈離開屏幕后則死亡if (bullet.isInvalid()) {bullet.die()}//射擊bullet.shoot()//顯示子彈圖片BulletShootingSprite(bullet)}}}/*** 更新子彈x、y值,顯示子彈圖片*/ @InternalCoroutinesApi @Composable fun BulletShootingSprite(bullet: Bullet = Bullet() ) {//繪制圖片Box(modifier = Modifier.fillMaxSize()) {Image(painter = painterResource(id = bullet.drawableId),contentScale = ContentScale.FillBounds,contentDescription = null,modifier = Modifier.offset {IntOffset(bullet.x,bullet.y)}.width(bullet.width).height(bullet.height).alpha(if (bullet.isAlive()) {1f} else {0f}))} }/*** 生成子彈*/private fun createBullet() {//游戲開始并且飛機在屏幕內才會生成if (gameStateFlow.value == GameState.Running && playerPlaneStateFlow.value.y < getApplication<Application>().resources.displayMetrics.heightPixels) {val bulletAward = playerPlaneStateFlow.value.bulletAwardvar bulletNum = bulletAward and 0xFFFF //數量val bulletType = bulletAward shr 16 //類型val bulletList = bulletListStateFlow.value as ArrayListval firstBullet = bulletList.firstOrNull { it.isDead() }if (firstBullet == null) {var newBullet = Bullet(type = BULLET_SINGLE,drawableId = R.drawable.sprite_bullet_single,width = BULLET_SPRITE_WIDTH.dp,hit = 1,state = SpriteState.LIFE,init = false)//子彈獎勵if (bulletNum > 0 && bulletType == BULLET_DOUBLE) {newBullet = newBullet.copy(type = BULLET_DOUBLE,drawableId = R.drawable.sprite_bullet_double,width = 18.dp,hit = 2,state = SpriteState.LIFE,init = false)//消耗子彈bulletNum--onPlayerAwardBullet(BULLET_DOUBLE shl 16 or bulletNum)}bulletList.add(newBullet)} else {var newBullet = firstBullet.copy(type = BULLET_SINGLE,drawableId = R.drawable.sprite_bullet_single,width = BULLET_SPRITE_WIDTH.dp,hit = 1,state = SpriteState.LIFE,init = false)//子彈獎勵if (bulletNum > 0 && bulletType == BULLET_DOUBLE) {newBullet = firstBullet.copy(type = BULLET_DOUBLE,drawableId = R.drawable.sprite_bullet_double,width = 18.dp,hit = 2,state = SpriteState.LIFE,init = false)//消耗子彈bulletNum--onPlayerAwardBullet(BULLET_DOUBLE shl 16 or bulletNum)}bulletList.add(newBullet)bulletList.removeAt(0)}onBulletListStateFlowChange(bulletList)}}/*** 初始化子彈出生位置*/private fun initBullet(bullet: Bullet) {val playerPlane = playerPlaneStateFlow.valueval playerPlaneWidthPx = dp2px(playerPlane.width)val bulletWidthPx = dp2px(bullet.width)val bulletHeightPx = dp2px(bullet.height)val startX = (playerPlane.x + playerPlaneWidthPx!! / 2 - bulletWidthPx!! / 2)val startY = (playerPlane.y - bulletHeightPx!!)bullet.startX = startXbullet.startY = startYbullet.x = bullet.startXbullet.y = bullet.startYbullet.init = true}

一開始只做了一顆子彈的射擊效果,使用一個重復動畫,不斷的調整子彈的x、y值,從玩家飛機頭部不斷的沿Y軸負方向飛行指定的距離,到達指定距離后再周而復始的從玩家飛機頭部繼續飛行,但是這樣的效果體驗不好,必須等待子彈飛行完指定距離后才能重復利用。
?

后來在此基礎上改用一個List維護Bullet對象,復用List里的Bullet對象,每次動畫值發生改變時,for循環更新所有子彈的狀態,并且Bullet對象發生碰撞或非出飛出屏幕即可重新復用,這樣一來效果比之前的好很多了。
?

6.敵機飛行和爆炸

實現效果:

定義一個EnemyPlane繼承Sprite,代碼如下:

/*** 敵機精靈*/ const val SMALL_ENEMY_PLANE_SPRITE_SIZE = 40 const val MIDDLE_ENEMY_PLANE_SPRITE_SIZE = 60 const val BIG_ENEMY_PLANE_SPRITE_SIZE = 100@InternalCoroutinesApi data class EnemyPlane(override var id: Long = System.currentTimeMillis(), //idoverride var name: String = "敵軍偵察機",@DrawableRes override val drawableIds: List<Int> = listOf(R.drawable.sprite_small_enemy_plane), //飛機資源圖標@DrawableRes override val bombDrawableId: Int = R.drawable.sprite_small_enemy_plane_seq, //敵機爆炸幀動畫資源override var segment: Int = 3, //爆炸效果由segment個片段組成,小飛機是3,中飛機是4,大飛機是6override var x: Int = 0, //敵機當前在X軸上的位置override var y: Int = -100, //敵機當前在Y軸上的位置override var startY: Int = -100, //出現的起始位置override var width: Dp = SMALL_ENEMY_PLANE_SPRITE_SIZE.dp, //寬override var height: Dp = SMALL_ENEMY_PLANE_SPRITE_SIZE.dp, //高override var velocity: Int = 1, //飛行速度(每幀移動的像素)var bombX: Int = -100, //爆炸動畫當前在X軸上的位置var bombY: Int = -100, //爆炸動畫當前在Y軸上的位置val power: Int = 1, //生命值,敵機的抗打擊能力var hit: Int = 0, //被擊中消耗的生命值val value: Int = 10, //打一個敵機的得分) : Sprite() {fun beHit(reduce: Int) {hit += reduce}fun isNoPower() = (power - hit) <= 0fun bomb() {hit = power}override fun reBirth() {state = SpriteState.LIFEhit = 0}override fun die() {state = SpriteState.DEATHbombX = xbombY = y}}

6.1敵機飛行

分析:

關鍵代碼:

/*** 敵機* 只能沿著Y軸飛行(不能沿X軸運動)*/@InternalCoroutinesApi @ExperimentalAnimationApi @Composable fun EnemyPlaneSprite(gameState: GameState,gameScore: Int,enemyPlaneList: List<EnemyPlane>,gameAction: GameAction ) {for (enemyPlane in enemyPlaneList) {EnemyPlaneSpriteMoveAndBomb(gameState,gameScore,enemyPlane,gameAction)} }@InternalCoroutinesApi @ExperimentalAnimationApi @Composable fun EnemyPlaneSpriteMoveAndBomb(gameState: GameState,gameScore: Int,enemyPlane: EnemyPlane,gameAction: GameAction ) {//爆炸動畫控制標志位,每個敵機都有一個獨立的標志位,方便觀察,不能放到EnemyPlane,因為不方便直接觀察var showBombAnim by remember {mutableStateOf(false)}EnemyPlaneSpriteMove(gameState,onBombAnimChange = {showBombAnim = it},enemyPlane,gameAction)EnemyPlaneSpriteBomb(gameScore, enemyPlane, showBombAnim,onBombAnimChange = {showBombAnim = it})}@InternalCoroutinesApi @ExperimentalAnimationApi @Composable fun EnemyPlaneSpriteMove(gameState: GameState,onBombAnimChange: (Boolean) -> Unit,enemyPlane: EnemyPlane,gameAction: GameAction ) {//重復動畫,1秒60幀(很奇怪,測試發現,如果不使用frame這個變量,則動畫不會循環進行)val infiniteTransition = rememberInfiniteTransition()val frame by infiniteTransition.animateInt(initialValue = 0,targetValue = 60,animationSpec = infiniteRepeatable(animation = tween(1000, easing = LinearEasing),repeatMode = RepeatMode.Restart))//游戲不在進行中if (gameState != GameState.Running) {return}//敵機飛行,包含碰撞檢測gameAction.moveEnemyPlane(enemyPlane,onBombAnimChange)LogUtil.printLog(message = "EnemyPlaneSpriteFly: state = ${enemyPlane.state},enemyPlane.x = ${enemyPlane.x}, enemyPlane.y = ${enemyPlane.y}, frame = $frame ")//繪制Box(modifier = Modifier.fillMaxSize()) {Image(painter = painterResource(enemyPlane.getRealDrawableId()),contentScale = ContentScale.FillBounds,contentDescription = null,modifier = Modifier.offset { IntOffset(enemyPlane.x, enemyPlane.y) }//.background(Color.Red).size(enemyPlane.width).alpha(if (enemyPlane.isAlive()) 1f else 0f))}}/*** 敵機移動*/private fun onEnemyPlaneMove(enemyPlane: EnemyPlane,onBombAnimChange: (Boolean) -> Unit) {viewModelScope.launch {withContext(Dispatchers.Default) {//獲取屏幕寬高val widthPixels = getApplication<Application>().resources.displayMetrics.widthPixelsval heightPixels =getApplication<Application>().resources.displayMetrics.heightPixels//敵機的大小和活動范圍val enemyPlaneWidthPx = dp2px(enemyPlane.width)val enemyPlaneHeightPx = dp2px(enemyPlane.height)val maxEnemyPlaneSpriteX = widthPixels - enemyPlaneWidthPx!! //X軸屏幕寬度向左偏移一個機身val maxEnemyPlaneSpriteY = heightPixels * 1.5 //Y軸1.5倍屏幕高度//如果未初始化,則給個隨機值(在屏幕范圍內)if (!enemyPlane.init) {enemyPlane.x = (0..maxEnemyPlaneSpriteX).random()var newY = -(0..heightPixels).random() - (0..heightPixels).random()when (enemyPlane.type) {0 -> newY -= enemyPlaneHeightPx!! * 21 -> newY -= enemyPlaneHeightPx!! * 42 -> newY -= enemyPlaneHeightPx!! * 10}enemyPlane.y = newYLogUtil.printLog(message = "enemyPlaneMove: newY $newY ")LogUtil.printLog(message = "enemyPlaneMove: id = ${enemyPlane.id},type = ${enemyPlane.type}, x = ${enemyPlane.x}, y = ${enemyPlane.y} ")enemyPlane.init = trueenemyPlane.reBirth()}//飛出屏幕(位移到指定距離),則死亡if (enemyPlane.y >= maxEnemyPlaneSpriteY) {enemyPlane.init = false//這里不能在die方法里調用,否則碰撞檢測爆炸后,敵機的位置馬上變化了enemyPlane.die()}//敵機位移enemyPlane.move()onCollisionDetect(enemyPlane, onBombAnimChange)}}}

可以看到,這里是用一個List集合統一管理敵機Sprite對象,而這個List對象是從GameViewModel傳過來的。
通過for循環調用EnemyPlaneSpriteMoveAndBomb函數,實現每個敵機Sprite對象的飛行和爆炸。在EnemyPlaneSpriteMoveAndBomb函數中,EnemyPlaneSpriteMove負責控制敵機Sprite對象的移動和顯示,EnemyPlaneSpriteBomb負責控制敵機Sprite對象爆炸動畫的播放和停止。
?

EnemyPlaneSpriteMove函數中主要使用rememberInfiniteTransition重復動畫來不斷驅動
EnemyPlaneSpriteMove函數調用,并通過GameAction的moveEnemyPlane函數修改敵機Sprite對象的x,y值,達到敵機飛行的效果。

6.2敵機爆炸

如果讓你來實現一鍵觸發所有敵機爆炸動畫的功能,你會怎么設計?
?

這里講下筆者的思路,一開始是打算直接在敵機Sprite對象里增加一個爆炸標志位,用于觀察是否播放爆炸動畫,但是發現根本觀察不到,因為直接更新List里對象的屬性,并不能觀察到變化,對于_MutableStateFlow_而言,只有調用emit函數才能通知觀察者,而且每個敵機發生爆炸都是獨立的,統一放到MutableStateFlow更新再調用emit函數,這個操作顯然太笨重了。
?

那每個敵機Sprite對象都在Compose函數中定義一個showBombAnim爆炸動畫標志位如何?當敵機Sprite對象生命值為0的時候,馬上去修改這個標志位,狀態發生改變就會驅動Compose組合函數,此時根據標志位來判斷是否需要播放爆炸動畫就可以了。

//爆炸動畫控制標志位,每個敵機都有一個獨立的標志位,方便觀察,不能放到EnemyPlane,因為不方便直接觀察var showBombAnim by remember {mutableStateOf(false)}EnemyPlaneSpriteMove(gameState,onBombAnimChange = {showBombAnim = it},enemyPlane,gameAction)EnemyPlaneSpriteBomb(gameScore,enemyPlane,showBombAnim,onBombAnimChange = {showBombAnim = it})

看以上代碼,同樣使用了狀態提升。EnemyPlaneSpriteMove函數的onBombAnimChange用于敵機生命值為零時,控制爆炸動畫播放。EnemyPlaneSpriteBomb函數的onBombAnimChange用于爆炸動畫播放完畢后隱藏爆炸圖片。
?

這樣一來,一鍵觸發所有敵機的爆炸動畫就很簡單了,將所有敵機對象的生命值變為0即可。

/*** 屏幕內所有敵機爆炸*/private fun onDestroyAllEnemy() {viewModelScope.launch {//敵機全部消失val listEnemyPlane = enemyPlaneListStateFlow.valuevar countScore = 0withContext(Dispatchers.Default) {for (enemyPlane in listEnemyPlane) {//存活并且在屏幕內if (enemyPlane.isAlive() && !enemyPlane.isNoPower() && enemyPlane.y > 0 && enemyPlane.y < getApplication<Application>().resources.displayMetrics.heightPixels) {countScore += enemyPlane.valueenemyPlane.bomb()//能量歸零就爆炸}}_enemyPlaneListStateFlow.emit(listEnemyPlane)}//更新分數gameScoreStateFlow.value.plus(countScore).let { onGameScoreStateFlowChange(it) }//爆炸道具減1val bombAward = playerPlaneStateFlow.value.bombAwardvar bombNum = bombAward and 0xFFFF //數量val bombType = bombAward shr 16 //類型if (bombNum-- <= 0) {bombNum = 0}onPlayerAwardBomb(bombType shl 16 or bombNum)}}

關于爆炸動畫,放到下一章節講解。

7.碰撞檢測和爆炸動畫

7.1碰撞檢測

碰撞檢測有很多種,這里用的是矩形碰撞,感興趣的小伙伴可以直接搜索學習。

如上圖,以敵機為視角,敵機所屬的紅色區域是危險區域,子彈和玩家飛機的矩形框只要觸碰紅色區域則代表發生碰撞檢測,而綠色區域則是安全區域。

關鍵代碼:

/*** 精靈工具類*/ object SpriteUtil {/*** 矩形碰撞的函數* @param x1 第一個矩形的X坐標* @param y1 第一個矩形的Y坐標* @param w1 第一個矩形的寬* @param h1 第一個矩形的高* @param x2 第二個矩形的X坐標* @param y2 第二個矩形的Y坐標* @param w2 第二個矩形的寬* @param h2 第二個矩形的高*/fun isCollisionWithRect(x1: Int,y1: Int,w1: Int,h1: Int,x2: Int,y2: Int,w2: Int,h2: Int): Boolean {if (x1 >= x2 && x1 >= x2 + w2) {return false} else if (x1 <= x2 && x1 + w1 <= x2) {return false} else if (y1 >= y2 && y1 >= y2 + h2) {return false} else if (y1 <= y2 && y1 + h1 <= y2) {return false}return true}}/*** 針對敵機的碰撞檢測*/private fun onCollisionDetect(enemyPlane: EnemyPlane,onBombAnimChange: (Boolean) -> Unit) {viewModelScope.launch {withContext(Dispatchers.Default) {//如果使用了炸彈,會導致所有敵機的生命變成0,觸發爆炸動畫if (enemyPlane.isAlive() && enemyPlane.isNoPower()) {//敵機死亡enemyPlane.die()//爆炸動畫可顯示onBombAnimChange(true)}//敵機的大小val enemyPlaneWidthPx = dp2px(enemyPlane.width)val enemyPlaneHeightPx = dp2px(enemyPlane.height)//玩家飛機大小val playerPlane = playerPlaneStateFlow.valueval playerPlaneWidthPx = dp2px(playerPlane.width)val playerPlaneHeightPx = dp2px(playerPlane.height)//如果敵機碰撞到了玩家飛機(碰撞檢測要求,碰撞雙方必須都在屏幕內)if (enemyPlane.isAlive() && playerPlane.x > 0 && playerPlane.y > 0 && enemyPlane.x > 0 && enemyPlane.y > 0 && SpriteUtil.isCollisionWithRect(playerPlane.x,playerPlane.y,playerPlaneWidthPx!!,playerPlaneHeightPx!!,enemyPlane.x,enemyPlane.y,enemyPlaneWidthPx!!,enemyPlaneHeightPx!!)) {//玩家飛機爆炸,進入GameState.Dying狀態,播放爆炸動畫,動畫結束后進入GameState.Over,彈出提示框,選擇重新開始或退出if (gameStateFlow.value == GameState.Running) {if (playerPlane.isNoProtect()) {onGameAction.die()}}}//子彈大小val bulletList = bulletListStateFlow.valueif (bulletList.isEmpty()) {return@withContext}val firstBullet = bulletList.first()val bulletSpriteWidthPx = dp2px(firstBullet.width)val bulletSpriteHeightPx = dp2px(firstBullet.height)//遍歷子彈和敵機是否發生碰撞bulletList.forEach { bullet ->//如果敵機存活且碰撞到了子彈(碰撞檢測要求,碰撞雙方必須都在屏幕內)if (enemyPlane.isAlive() && bullet.isAlive() && bullet.x > 0 && bullet.y > 0 && SpriteUtil.isCollisionWithRect(bullet.x,bullet.y,bulletSpriteWidthPx!!,bulletSpriteHeightPx!!,enemyPlane.x,enemyPlane.y,enemyPlaneWidthPx!!,enemyPlaneHeightPx!!)) {bullet.die()enemyPlane.beHit(bullet.hit)//敵機無能量后就爆炸if (enemyPlane.isNoPower()) {//敵機死亡enemyPlane.die()//爆炸動畫可顯示onBombAnimChange(true)//游戲得分,爆炸動畫是觀察分數變化來觸發的onGameScore(gameScoreStateFlow.value + enemyPlane.value)//播放爆炸音效onPlayByRes(getApplication(), R.raw.explosion)return@forEach}}}}}}

在敵機移動的onEnemyPlaneMove函數中,每次都會調用onCollisionDetect進行碰撞檢測,對于敵機對象而言,需要調用isCollisionWithRect分別傳入子彈和玩家飛機對象的矩形數據進行比較,得出碰撞檢測結果,根據結果執行對應的游戲邏輯。
?

7.2爆炸動畫

爆炸動畫的素材如下,這實際上就是幀動畫了。

關鍵代碼:

/*** 測試爆炸動畫*/ @InternalCoroutinesApi @Composable fun TestComposeShowBombSprite() {val bomb by remember { mutableStateOf(Bomb(x = 500, y = 500)) }var state by remember {mutableStateOf(0)}val anim = remember {TargetBasedAnimation(animationSpec = tween(durationMillis = bomb.segment * 33,//相當一秒播放30幀, 1000/30 = 33easing = LinearEasing),typeConverter = Int.VectorConverter,initialValue = 0,targetValue = bomb.segment - 1)}var playTime by remember { mutableStateOf(0L) }var animationSegmentIndex by remember {mutableStateOf(0)}LaunchedEffect(state) {val startTime = withFrameNanos { it }do {playTime = withFrameNanos { it } - startTimeanimationSegmentIndex = anim.getValueFromNanos(playTime)} while (!anim.isFinishedFromNanos(playTime))}Box(modifier = Modifier.fillMaxSize(1f), contentAlignment = Alignment.Center) {Box(modifier = Modifier.size(60.dp).background(Color.Red, shape = RoundedCornerShape(60 / 5)).clickable {LogUtil.printLog(message = "觸發動畫 ")state++bomb.reBirth()}, contentAlignment = Alignment.Center) {Text(text = animationSegmentIndex.toString(),style = TextStyle(color = Color.White, fontSize = 12.sp))}}//LogUtil.printLog(message = "TestComposeShowBombSprite() animationSegmentIndex $animationSegmentIndex")//LogUtil.printLog(message = "TestComposeShowBombSprite() bomb.state ${bomb.state}")PlayBombSpriteAnimate(bomb, animationSegmentIndex) }@InternalCoroutinesApi @Composable fun PlayBombSpriteAnimate(bomb: Bomb, animationSegmentIndex: Int) {//越界檢測if (animationSegmentIndex >= bomb.segment) {return}//初始化炸彈的大小val bombWidth = bomb.widthval bombWidthWidthPx = with(LocalDensity.current) { bombWidth.toPx() }//這里使用修改ImageBitmap.imageResource返回bitmap方便處理val bitmap: Bitmap = imageResource(bomb.bombDrawableId)//分割Bitmapval displayBitmapWidth = bitmap.width / bomb.segment//Matrix用來放大到跟bombWidthWidthPx一樣大小val matrix = Matrix()matrix.postScale(bombWidthWidthPx / displayBitmapWidth,bombWidthWidthPx / bitmap.height)//越界檢測if ((animationSegmentIndex * displayBitmapWidth) + displayBitmapWidth > bitmap.width) {return}//只獲取需要的部分val displayBitmap = Bitmap.createBitmap(bitmap,(animationSegmentIndex * displayBitmapWidth),0,displayBitmapWidth,bitmap.height,matrix,true)val imageBitmap: ImageBitmap = displayBitmap.asImageBitmap()Canvas(modifier = Modifier.fillMaxSize().size(bombWidth)) {drawImage(imageBitmap,topLeft = Offset(bomb.x.toFloat(),bomb.y.toFloat(),),alpha = if (bomb.isAlive()) 1.0f else 0f,)} }/*** Load an ImageBitmap from an image resource.** This function is intended to be used for when low-level ImageBitmap-specific* functionality is required. For simply displaying onscreen, the vector/bitmap-agnostic* [painterResource] is recommended instead.** @param id the resource identifier* @return the decoded image data associated with the resource*/ @Composable fun imageResource(@DrawableRes id: Int): Bitmap {val context = LocalContext.currentval value = remember { TypedValue() }context.resources.getValue(id, value, true)val key = value.string!!.toString() // image resource must have resource path.return remember(key) { imageResource(context.resources, id) } }

思路如下:

  • 如何加載幀動畫素材?使用imageResource函數加載幀動畫素材即可得到一個Bitmap對象。
  • 動畫素材和對應的Sprite對象寬高不一致?使用Matrix的postScale函數進行縮放即可,這里只要保持高度一致。
  • 得到的幀動畫Bitmap怎么用?使用Bitmap.createBitmap函數獲取局部的Bitmap并顯示即可。這里定義一個animationSegmentIndex作為當前要顯示的動畫幀的下標,通過橫向切割,在Btimap高度一致的情況下,只要計算createBitmap函數的x參數即可通過偏移量定位并獲取到當前動畫幀的Bitmap,最后通過asImageBitmap把Bitmap轉成ImageBitmap,使用drawImage顯示圖片。
  • 如何確定當前的動畫幀下標?使用TargetBasedAnimation動畫得到animationSegmentIndex從0到對應爆炸動畫素材總幀數的變化過程,即可驅動Compose函數顯示對應動畫幀,當然時間上也要控制以下,這樣連續的播放動畫幀,動畫效果就出來了。
  • 如何觸發動畫?由于LaunchedEffect動畫可以觀察狀態來觸發,因此想要播放爆炸動畫的時候,我們只需要修改LaunchedEffect觀察的狀態即可,動畫播放結束后再改回去,注意動畫是否顯示是通過alpha值來控制的。
  • ?

    8.其它

    有了以上知識點的鋪墊,其它功能,如分數的顯示和計算,道具獎勵的生成和獲取等就很簡單了,這里不在贅述,有興趣可查看源碼,注釋還是比較詳細的。

    9.游戲控制

    游戲控制可以認為就是游戲狀態管理,定義GameState和GameAction,通過GameViewModel來管理,高內聚低耦合可復用。其中GameState定義了游戲的狀態,通過GameAction驅動狀態轉換,構造一個完整的有限狀態機。要注意的是State和Action并不是一一對應的。

    參考資料《深入淺出理解有限狀態機》

    ?

    • Wating:游戲開始狀態,看圖就懂了。
    • Running:游戲中狀態,看圖就懂了。
    • Paused:游戲暫停狀態,同上,看圖就懂了,就是一切元素和狀態都不會發生變化。

    • Dying:玩家飛機死亡狀態,用于觸發玩家飛機爆炸動畫,這個看起來沒有必要放到GameState里吧?確實沒有必要,去掉完全不影響,也可以通過在Compose可組合函數內部定義一個state來實現。但如果你有其它需求,比如玩家飛機爆炸時,子彈、敵機全部消失,加上這個Dying就很方便處理了,各有各的好,架構也不是死的,可以根據實際需要進行調整。

    • Over:游戲結束狀態,玩家飛機爆炸動畫播放完畢就自動進入Over狀態,如下圖。

    • Exit:用于退出游戲,看起來也是多余的?退出游戲就是調用Activity的finish方法,但是在GameViewModel并不會直接依賴Activity,那就調不到finish方法了,怎么辦?推薦的方式是在Activity中觀察GameViewModel提供的公開的狀態,實現ViewModel和Activity通信,參考代碼如下:
    //觀察游戲狀態lifecycleScope.launch {gameViewModel.gameStateFlow.collect {LogUtil.printLog(message = "lifecycleScope gameState $it")//退出appif (GameState.Exit == it) {finish()}}}

    關鍵代碼:

    /*** 游戲狀態*/ enum class GameState {Waiting, // wait to startRunning, // gamingPaused, // pauseDying, // hit enemy and dyingOver, // overExit // finish activity }/*** 游戲動作*/ @InternalCoroutinesApi data class GameAction(val start: () -> Unit = {}, //游戲狀態進入Running,游戲中val pause: () -> Unit = {},//游戲狀態進入Paused,暫停val reset: () -> Unit = {},//游戲狀態進入Waiting,顯示GameWaitingval die: () -> Unit = {},//游戲狀態進入Dying,觸發爆炸動畫val over: () -> Unit = {},//游戲狀態進入Over,顯示GameOverBoardval exit: () -> Unit = {},//退出游戲val playerMove: (x: Int, y: Int) -> Unit = { _: Int, _: Int -> },//玩家移動val score: (score: Int) -> Unit = { _: Int -> },//更新分數val award: (award: Award) -> Unit = { _: Award -> },//獲得獎勵val createBullet: () -> Unit = { },//子彈生成val initBullet: (bullet: Bullet) -> Unit = { _: Bullet -> },//子彈初始化出生位置val shooting: (resId: Int) -> Unit = { _: Int -> },//射擊val destroyAllEnemy: () -> Unit = {},//摧毀所有敵機val levelUp: (score: Int) -> Unit = { _: Int -> },//難度升級 )/*** 游戲狀態StateFlow*/private val _gameStateFlow = MutableStateFlow(GameState.Waiting)val gameStateFlow = _gameStateFlow.asStateFlow()private fun onGameStateFlowChange(newGameSate: GameState) {viewModelScope.launch {withContext(Dispatchers.Default) {_gameStateFlow.emit(newGameSate)}}}

    在整個游戲邏輯中,主要是通過界面操作,碰撞檢測,生命周期回調,觸發各種Action,最終調用onGameStateFlowChange更新狀態。
    ?

    在Compose可組合函數中,根據不同的State對界面進行不同的顯示。如以下代碼,通過LaunchedEffect(gameState)觀察游戲狀態,當gameState == GameState.Dying條件滿足時,才觸發爆炸動畫,顯示并播放爆炸資源圖片序列。

    /*** 玩家飛機爆炸動畫*/ @InternalCoroutinesApi @ExperimentalAnimationApi @Composable fun PlayerPlaneBombSprite(gameState: GameState = GameState.Waiting,playerPlane: PlayerPlane,gameAction: GameAction ) {if (gameState != GameState.Dying) {return}val spriteSize = PLAYER_PLANE_SPRITE_SIZE.dpval spriteSizePx = with(LocalDensity.current) { spriteSize.toPx() }val segment = playerPlane.segmentval anim = remember {TargetBasedAnimation(animationSpec = tween(172),typeConverter = Int.VectorConverter,initialValue = 0,targetValue = segment - 1)}var animationValue by remember {mutableStateOf(0)}var playTime by remember { mutableStateOf(0L) }LaunchedEffect(gameState) {val startTime = withFrameNanos { it }do {playTime = withFrameNanos { it } - startTimeanimationValue = anim.getValueFromNanos(playTime)} while (!anim.isFinishedFromNanos(playTime))}LogUtil.printLog(message = "PlayerPlaneBombSprite() animationValue $animationValue")//這里使用修改ImageBitmap.imageResource返回bitmap方便處理val bitmap: Bitmap = imageResource(R.drawable.sprite_player_plane_bomb_seq)//分割Bitmapval displayBitmapWidth = bitmap.width / segmentval matrix = Matrix()matrix.postScale(spriteSizePx / displayBitmapWidth, spriteSizePx / bitmap.height)//只獲取需要的部分val displayBitmap = Bitmap.createBitmap(bitmap,(animationValue * displayBitmapWidth),0,displayBitmapWidth,bitmap.height,matrix,true)val imageBitmap: ImageBitmap = displayBitmap.asImageBitmap()Canvas(modifier = Modifier.fillMaxSize().size(spriteSize)) {val canvasWidth = size.widthval canvasHeight = size.heightdrawImage(imageBitmap,topLeft = Offset(playerPlane.x.toFloat(),playerPlane.y.toFloat(),),alpha = if (gameState == GameState.Dying) 1.0f else 0f,)}if (animationValue == segment - 1) {gameAction.over()} }

    以此類推,要實現游戲暫停效果,說白了就是控制游戲中的所有元素停止移動,并且所有Action除了start之外全部不可用。實現這個效果,只要對應Action和Compose組合函數的實現要加上以下代碼即可解決。

    //游戲不在進行中if (gameState != GameState.Running) {return}

    是不是很簡單,就是這么簡單。恢復游戲只要把State改成GameState.Running即可。

    10.總結

    還是花費了很多時間去實現這個游戲的,因為Jetpack Compose是剛接觸的知識點,并且之前也沒游戲開發的經驗,只能不斷的試錯,并反復閱讀大佬們的文章,閱讀官方文檔,閱讀源碼摳細節,包括Kotlin語言的再學習,整個過程還是收獲良多。

    相比于寫代碼,寫這個文章節奏要慢很多,一方面希望能夠把知識點講的通俗易懂,一方面又不能太啰嗦,直到最后寫完還是感覺篇幅過長了。
    ?

    對于這個游戲來說,有很多遺憾:如敵機的生成,出生的起點位置不夠分散,容易出現敵機重疊的情況;關卡的設計太簡單,可玩性不高;游戲分數沒有做記錄等等。
    ?

    實際上這篇文章中秋的時候就寫完了,但是感覺寫的不太滿意,寫的時候代碼也在不斷修改中,部分代碼甚至跟文章對應不上,就不想發出來了。上周末的時候突然想起,然后又優化了下,想了想,從學習Jetpack Compose的角度來說,寫完這篇文章,目標已經達成了,還是分享出來吧,如果剛好對大家有一些幫助,那就更好了,感謝閱讀。

    11.參考資料

    TechMerger大佬的《一氣呵成:用Compose完美復刻Flappy Bird!》
    ?

    fundroid大佬的《用Jetpack Compose做一個俄羅斯方塊游戲機》《100 行寫一個 Compose 版華容道》
    ?

    孫群大佬的[《[GitHub開源]Android自定義View實現微信打飛機游戲]》](https://blog.csdn.net/iispring/article/details/51999881)
    ?

    官方文檔《使用 Jetpack Compose 更快地打造更出色的應用》
    ?

    不一一列舉了,文章中涉及的知識點基本都加上了鏈接,方便大家閱讀學習。

    總結

    以上是生活随笔為你收集整理的学不动了,尝试用Android Jetpack Compose重写微信经典飞机大战游戏的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    日韩少妇内射免费播放 | 欧洲熟妇精品视频 | 性欧美疯狂xxxxbbbb | 爽爽影院免费观看 | 亚洲国产精华液网站w | 中文字幕日产无线码一区 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 亚洲啪av永久无码精品放毛片 | 久久精品国产99精品亚洲 | 久久精品国产一区二区三区 | 亚洲成a人片在线观看无码3d | 水蜜桃av无码 | 东京一本一道一二三区 | 真人与拘做受免费视频一 | 激情人妻另类人妻伦 | 亚洲色成人中文字幕网站 | 综合激情五月综合激情五月激情1 | 久久99精品国产.久久久久 | 国产97人人超碰caoprom | 久久熟妇人妻午夜寂寞影院 | 国产成人无码午夜视频在线观看 | 亚洲区小说区激情区图片区 | 麻豆蜜桃av蜜臀av色欲av | 玩弄中年熟妇正在播放 | 无码av岛国片在线播放 | 成人精品视频一区二区三区尤物 | 男女下面进入的视频免费午夜 | a片在线免费观看 | 精品国产aⅴ无码一区二区 | 免费人成网站视频在线观看 | 亚洲精品一区二区三区四区五区 | 夜先锋av资源网站 | v一区无码内射国产 | 内射白嫩少妇超碰 | 无码帝国www无码专区色综合 | 在线欧美精品一区二区三区 | 97久久精品无码一区二区 | 性史性农村dvd毛片 | 久久人人爽人人爽人人片ⅴ | 无码一区二区三区在线 | 婷婷五月综合激情中文字幕 | 午夜精品一区二区三区的区别 | 男女作爱免费网站 | 亚洲熟女一区二区三区 | 亚洲中文字幕无码中文字在线 | 国产片av国语在线观看 | 亚洲爆乳精品无码一区二区三区 | 亚洲娇小与黑人巨大交 | 欧美肥老太牲交大战 | 麻豆成人精品国产免费 | 成人片黄网站色大片免费观看 | 伊在人天堂亚洲香蕉精品区 | 国产超碰人人爽人人做人人添 | 老熟妇乱子伦牲交视频 | 亚洲精品一区二区三区四区五区 | 久久久久亚洲精品男人的天堂 | 亚洲日本va中文字幕 | 久久精品国产亚洲精品 | 一本久道久久综合婷婷五月 | 国产成人无码av一区二区 | 麻豆国产人妻欲求不满 | 无码人妻精品一区二区三区下载 | 玩弄少妇高潮ⅹxxxyw | 人人妻人人澡人人爽欧美一区 | 亚洲成a人片在线观看无码3d | 久久综合九色综合97网 | 天天燥日日燥 | 亚洲精品午夜国产va久久成人 | 久久99精品国产麻豆蜜芽 | 午夜男女很黄的视频 | 亚洲一区二区三区无码久久 | 无码国产乱人伦偷精品视频 | 国产精品成人av在线观看 | 蜜臀aⅴ国产精品久久久国产老师 | 亚洲日韩精品欧美一区二区 | 欧洲欧美人成视频在线 | 亚洲日韩av片在线观看 | 日韩视频 中文字幕 视频一区 | 亚洲国产精品无码一区二区三区 | 亚洲 a v无 码免 费 成 人 a v | 激情人妻另类人妻伦 | 三上悠亚人妻中文字幕在线 | 亚洲毛片av日韩av无码 | 亚洲综合精品香蕉久久网 | 国产亚洲精品久久久久久 | 久久99精品国产麻豆蜜芽 | 国产精品免费大片 | 精品久久8x国产免费观看 | 日日噜噜噜噜夜夜爽亚洲精品 | 狂野欧美性猛交免费视频 | 亚洲成熟女人毛毛耸耸多 | 香港三级日本三级妇三级 | 日日夜夜撸啊撸 | 久久精品视频在线看15 | 无码精品国产va在线观看dvd | 亚洲精品成人福利网站 | 97色伦图片97综合影院 | 欧美 日韩 亚洲 在线 | 国产情侣作爱视频免费观看 | 人人妻人人澡人人爽人人精品浪潮 | 免费无码肉片在线观看 | 东京无码熟妇人妻av在线网址 | 丰满少妇高潮惨叫视频 | 国产精品美女久久久 | 宝宝好涨水快流出来免费视频 | 东京一本一道一二三区 | 久久国内精品自在自线 | 国产精品久久久 | 色偷偷人人澡人人爽人人模 | 国产精品18久久久久久麻辣 | 大地资源中文第3页 | 乌克兰少妇性做爰 | 曰韩少妇内射免费播放 | 久久国产自偷自偷免费一区调 | 国产精品第一国产精品 | 国产国语老龄妇女a片 | 日本护士毛茸茸高潮 | 无码播放一区二区三区 | 无码人妻精品一区二区三区不卡 | 人妻尝试又大又粗久久 | 国产精品va在线播放 | 国产手机在线αⅴ片无码观看 | 免费无码午夜福利片69 | 清纯唯美经典一区二区 | 国产明星裸体无码xxxx视频 | 国产特级毛片aaaaaa高潮流水 | 欧美变态另类xxxx | 玩弄中年熟妇正在播放 | 国产午夜精品一区二区三区嫩草 | 亚洲国产欧美在线成人 | 黑人巨大精品欧美一区二区 | 欧美大屁股xxxxhd黑色 | 亚洲成a人片在线观看无码 | 国产精品自产拍在线观看 | 国产午夜福利亚洲第一 | 色 综合 欧美 亚洲 国产 | 一本加勒比波多野结衣 | 欧美猛少妇色xxxxx | 国产精品久久久久无码av色戒 | 永久免费观看国产裸体美女 | 久久成人a毛片免费观看网站 | 日韩人妻无码中文字幕视频 | 中文字幕av伊人av无码av | 欧美日韩久久久精品a片 | 亚洲国产综合无码一区 | 偷窥日本少妇撒尿chinese | 377p欧洲日本亚洲大胆 | 久久伊人色av天堂九九小黄鸭 | 鲁大师影院在线观看 | 久久精品无码一区二区三区 | 无码人妻精品一区二区三区下载 | 我要看www免费看插插视频 | 妺妺窝人体色www在线小说 | 精品乱码久久久久久久 | 帮老师解开蕾丝奶罩吸乳网站 | 日日橹狠狠爱欧美视频 | 国产亚洲精品久久久ai换 | 日韩人妻系列无码专区 | 日本一本二本三区免费 | 无码中文字幕色专区 | 亚洲综合伊人久久大杳蕉 | 色婷婷香蕉在线一区二区 | 日韩视频 中文字幕 视频一区 | 国产精品爱久久久久久久 | 无码av岛国片在线播放 | 亚洲欧美精品aaaaaa片 | 国产成人综合美国十次 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 丰满人妻翻云覆雨呻吟视频 | 99er热精品视频 | 亚洲色www成人永久网址 | 精品国产一区av天美传媒 | 性欧美videos高清精品 | 狠狠躁日日躁夜夜躁2020 | 久久五月精品中文字幕 | 青青青爽视频在线观看 | 日韩av无码中文无码电影 | 色 综合 欧美 亚洲 国产 | a片免费视频在线观看 | 一本久久a久久精品vr综合 | www一区二区www免费 | 国产麻豆精品精东影业av网站 | 国产精品18久久久久久麻辣 | 亚洲日本va中文字幕 | 色综合久久88色综合天天 | 呦交小u女精品视频 | 日韩欧美中文字幕在线三区 | 欧美黑人性暴力猛交喷水 | 日韩av无码中文无码电影 | 麻豆人妻少妇精品无码专区 | 国产av一区二区三区最新精品 | 亚洲一区二区三区 | 男女下面进入的视频免费午夜 | 国产麻豆精品精东影业av网站 | 色综合久久88色综合天天 | 免费观看激色视频网站 | 高潮毛片无遮挡高清免费 | 亚洲自偷自偷在线制服 | 欧美阿v高清资源不卡在线播放 | 中文字幕乱码人妻无码久久 | 色一情一乱一伦一视频免费看 | 国产午夜亚洲精品不卡下载 | 国产精品久久久一区二区三区 | 蜜桃视频插满18在线观看 | 国产sm调教视频在线观看 | www国产精品内射老师 | 国产一区二区三区精品视频 | 亚洲国产精华液网站w | 欧美真人作爱免费视频 | 成人无码视频免费播放 | 免费看少妇作爱视频 | 日韩精品无码免费一区二区三区 | 大地资源网第二页免费观看 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 超碰97人人射妻 | 国产成人精品一区二区在线小狼 | 亚洲狠狠色丁香婷婷综合 | 欧美国产日韩亚洲中文 | 欧美变态另类xxxx | 无码av中文字幕免费放 | 双乳奶水饱满少妇呻吟 | 国产人妻人伦精品1国产丝袜 | 国产人妻久久精品二区三区老狼 | 中文精品久久久久人妻不卡 | av无码电影一区二区三区 | 午夜福利不卡在线视频 | 综合网日日天干夜夜久久 | 中文字幕 人妻熟女 | 97夜夜澡人人爽人人喊中国片 | 成人无码影片精品久久久 | 两性色午夜免费视频 | 国产无av码在线观看 | 亚洲娇小与黑人巨大交 | 国产精品亚洲专区无码不卡 | 国语自产偷拍精品视频偷 | 精品午夜福利在线观看 | 欧美刺激性大交 | 欧洲精品码一区二区三区免费看 | 亚洲日本一区二区三区在线 | 免费人成网站视频在线观看 | 久久综合九色综合97网 | 中文字幕无码日韩专区 | 午夜理论片yy44880影院 | 77777熟女视频在线观看 а天堂中文在线官网 | 久久精品一区二区三区四区 | 又大又黄又粗又爽的免费视频 | 亚洲狠狠色丁香婷婷综合 | 乱人伦中文视频在线观看 | 成人无码精品1区2区3区免费看 | 成人精品视频一区二区三区尤物 | 一本久久a久久精品vr综合 | 丰满人妻一区二区三区免费视频 | 亚洲熟妇色xxxxx欧美老妇 | 99久久久无码国产精品免费 | 又色又爽又黄的美女裸体网站 | a在线亚洲男人的天堂 | 亚洲精品一区二区三区在线观看 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 精品一二三区久久aaa片 | 国产绳艺sm调教室论坛 | 久久综合狠狠综合久久综合88 | 性欧美牲交在线视频 | 四虎国产精品一区二区 | 久久午夜夜伦鲁鲁片无码免费 | 国产成人av免费观看 | 18无码粉嫩小泬无套在线观看 | 国产午夜亚洲精品不卡下载 | 51国偷自产一区二区三区 | 青春草在线视频免费观看 | 亚洲人成网站色7799 | 亚拍精品一区二区三区探花 | 中文字幕av无码一区二区三区电影 | 一二三四在线观看免费视频 | 国产成人亚洲综合无码 | 日韩av无码一区二区三区不卡 | 老子影院午夜精品无码 | 婷婷色婷婷开心五月四房播播 | 丰满诱人的人妻3 | 无码播放一区二区三区 | 国产特级毛片aaaaaa高潮流水 | 青青久在线视频免费观看 | 18禁黄网站男男禁片免费观看 | 疯狂三人交性欧美 | 乱中年女人伦av三区 | 亚洲精品久久久久久久久久久 | 18精品久久久无码午夜福利 | 久久久久人妻一区精品色欧美 | 色诱久久久久综合网ywww | 亚洲日韩av一区二区三区中文 | 亚洲综合久久一区二区 | 亚洲一区二区三区播放 | 曰韩少妇内射免费播放 | 亚洲国产精品毛片av不卡在线 | 中文字幕无码视频专区 | 男人的天堂2018无码 | 亚洲国产av精品一区二区蜜芽 | 亚洲中文字幕无码中字 | 日韩av无码一区二区三区不卡 | 国产特级毛片aaaaaa高潮流水 | 日韩精品无码免费一区二区三区 | 日韩成人一区二区三区在线观看 | 国产人妻大战黑人第1集 | 欧洲极品少妇 | 国产精品爱久久久久久久 | 女人被爽到呻吟gif动态图视看 | 东北女人啪啪对白 | 国内揄拍国内精品少妇国语 | 麻豆国产人妻欲求不满谁演的 | 无码国模国产在线观看 | av香港经典三级级 在线 | 中文精品久久久久人妻不卡 | 少妇太爽了在线观看 | 国产免费久久精品国产传媒 | 天堂а√在线地址中文在线 | 亚洲国产精品毛片av不卡在线 | 成 人 免费观看网站 | 国产精品无码一区二区三区不卡 | 久久精品视频在线看15 | 免费国产成人高清在线观看网站 | www国产亚洲精品久久久日本 | 亚洲精品无码人妻无码 | 国产人妻精品一区二区三区 | 欧美真人作爱免费视频 | 免费观看黄网站 | 久久精品国产日本波多野结衣 | 久久国产精品二国产精品 | 国产精品.xx视频.xxtv | 国产9 9在线 | 中文 | 西西人体www44rt大胆高清 | 亚洲精品综合五月久久小说 | 日本高清一区免费中文视频 | 夫妻免费无码v看片 | 成人一在线视频日韩国产 | 久久国产自偷自偷免费一区调 | 久久精品99久久香蕉国产色戒 | 国产美女精品一区二区三区 | 骚片av蜜桃精品一区 | 人妻少妇被猛烈进入中文字幕 | 中文精品无码中文字幕无码专区 | 国产精品亚洲一区二区三区喷水 | 亚洲熟妇色xxxxx欧美老妇 | 久在线观看福利视频 | 亚洲日本va中文字幕 | 又大又黄又粗又爽的免费视频 | 久久99热只有频精品8 | 国产 浪潮av性色四虎 | 午夜熟女插插xx免费视频 | 国产成人无码a区在线观看视频app | 性色av无码免费一区二区三区 | 99久久久无码国产精品免费 | 野外少妇愉情中文字幕 | 2020久久超碰国产精品最新 | 在线精品国产一区二区三区 | 色一情一乱一伦 | 人人超人人超碰超国产 | 亚洲中文字幕无码中文字在线 | 无码av免费一区二区三区试看 | 西西人体www44rt大胆高清 | 日日夜夜撸啊撸 | 欧美日韩亚洲国产精品 | 国产成人精品视频ⅴa片软件竹菊 | 东京无码熟妇人妻av在线网址 | 99久久99久久免费精品蜜桃 | 国产无遮挡吃胸膜奶免费看 | 国产av无码专区亚洲awww | 夜夜影院未满十八勿进 | 久久亚洲精品成人无码 | 亚洲中文字幕在线无码一区二区 | 日本xxxx色视频在线观看免费 | 久久久久亚洲精品男人的天堂 | 天天摸天天碰天天添 | 国产亚洲欧美在线专区 | 久久99久久99精品中文字幕 | 99国产欧美久久久精品 | 国产综合在线观看 | 熟妇人妻无码xxx视频 | 九九热爱视频精品 | 国产精品无码一区二区桃花视频 | 国精品人妻无码一区二区三区蜜柚 | 超碰97人人射妻 | 国产手机在线αⅴ片无码观看 | 欧美 日韩 人妻 高清 中文 | 色偷偷人人澡人人爽人人模 | 无码人妻黑人中文字幕 | 国产亚洲人成在线播放 | 国产sm调教视频在线观看 | 在线天堂新版最新版在线8 | 国产午夜福利亚洲第一 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 天堂а√在线地址中文在线 | 成熟人妻av无码专区 | 久久精品女人的天堂av | 久久精品一区二区三区四区 | 日日天日日夜日日摸 | 老熟女乱子伦 | a在线亚洲男人的天堂 | 精品一区二区不卡无码av | 77777熟女视频在线观看 а天堂中文在线官网 | 欧洲欧美人成视频在线 | 精品午夜福利在线观看 | 人妻少妇精品无码专区动漫 | 亚洲成av人片天堂网无码】 | 漂亮人妻洗澡被公强 日日躁 | 久久精品女人的天堂av | 久久国产自偷自偷免费一区调 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 国产精品多人p群无码 | 秋霞成人午夜鲁丝一区二区三区 | 国产av剧情md精品麻豆 | 人妻互换免费中文字幕 | 色婷婷久久一区二区三区麻豆 | 国产精品久久久av久久久 | 欧美野外疯狂做受xxxx高潮 | 高清不卡一区二区三区 | 亚洲国产精品久久人人爱 | 激情内射日本一区二区三区 | 2020最新国产自产精品 | 国产成人午夜福利在线播放 | 亚洲欧洲中文日韩av乱码 | 亚洲 另类 在线 欧美 制服 | 99久久亚洲精品无码毛片 | 日欧一片内射va在线影院 | 2020久久超碰国产精品最新 | 97色伦图片97综合影院 | 国产精品久久国产精品99 | 欧美国产日韩久久mv | 天天爽夜夜爽夜夜爽 | 国产人妻精品一区二区三区 | 午夜精品久久久内射近拍高清 | 高潮毛片无遮挡高清免费 | 国产真实乱对白精彩久久 | 欧美日韩精品 | а√资源新版在线天堂 | 国产成人人人97超碰超爽8 | 久在线观看福利视频 | 欧美日本精品一区二区三区 | 欧美一区二区三区视频在线观看 | 少妇无码吹潮 | 精品久久久久久人妻无码中文字幕 | 88国产精品欧美一区二区三区 | 国色天香社区在线视频 | 亚洲国产精品一区二区第一页 | 精品无码一区二区三区的天堂 | 欧美性黑人极品hd | 精品国精品国产自在久国产87 | 国产国产精品人在线视 | 性做久久久久久久免费看 | 欧美xxxxx精品 | 国产在线精品一区二区三区直播 | 六十路熟妇乱子伦 | 最新国产乱人伦偷精品免费网站 | 日韩精品成人一区二区三区 | 一二三四社区在线中文视频 | 国产成人av免费观看 | 蜜桃视频韩日免费播放 | 欧美熟妇另类久久久久久多毛 | 日本va欧美va欧美va精品 | 久久久久久久人妻无码中文字幕爆 | 色综合视频一区二区三区 | 日本www一道久久久免费榴莲 | 在线天堂新版最新版在线8 | 亚洲爆乳精品无码一区二区三区 | 熟妇女人妻丰满少妇中文字幕 | 久久国内精品自在自线 | 日韩精品成人一区二区三区 | 精品欧美一区二区三区久久久 | 性色av无码免费一区二区三区 | 亚洲熟妇色xxxxx欧美老妇 | 亚洲日韩一区二区三区 | 亚洲娇小与黑人巨大交 | 日本一区二区三区免费播放 | 中文字幕无码av波多野吉衣 | 好屌草这里只有精品 | 日韩欧美群交p片內射中文 | 亚洲欧洲无卡二区视頻 | 日本一区二区三区免费播放 | 亚洲精品一区二区三区大桥未久 | 一本大道久久东京热无码av | 国产激情一区二区三区 | 精品国精品国产自在久国产87 | 国产成人精品必看 | 澳门永久av免费网站 | 国产无av码在线观看 | 国产舌乚八伦偷品w中 | 日本乱人伦片中文三区 | 激情五月综合色婷婷一区二区 | 亚洲日韩中文字幕在线播放 | 中国大陆精品视频xxxx | 久久精品女人的天堂av | 亚洲区小说区激情区图片区 | 伊人久久大香线蕉亚洲 | 成人女人看片免费视频放人 | 久久99精品国产麻豆蜜芽 | 人妻尝试又大又粗久久 | 欧美性生交活xxxxxdddd | 老熟妇乱子伦牲交视频 | 国内精品人妻无码久久久影院蜜桃 | 久久99精品国产麻豆 | 少妇人妻偷人精品无码视频 | 色 综合 欧美 亚洲 国产 | 成人免费视频视频在线观看 免费 | 又黄又爽又色的视频 | 久久综合狠狠综合久久综合88 | 亚洲中文字幕无码中字 | 色欲av亚洲一区无码少妇 | 成年美女黄网站色大免费视频 | 欧美怡红院免费全部视频 | v一区无码内射国产 | 国产精品无码一区二区三区不卡 | 久久综合给合久久狠狠狠97色 | 欧美人与牲动交xxxx | 日韩欧美成人免费观看 | 台湾无码一区二区 | 午夜成人1000部免费视频 | 水蜜桃色314在线观看 | 精品欧洲av无码一区二区三区 | 丝袜美腿亚洲一区二区 | 99riav国产精品视频 | 东京热男人av天堂 | 99久久人妻精品免费一区 | 国产成人一区二区三区别 | 精品久久久久香蕉网 | 成人免费视频在线观看 | 免费看少妇作爱视频 | 人人妻人人澡人人爽欧美精品 | 在线播放亚洲第一字幕 | 中文字幕av无码一区二区三区电影 | 国产99久久精品一区二区 | 国产av人人夜夜澡人人爽麻豆 | 国产人成高清在线视频99最全资源 | 国产午夜福利100集发布 | 欧美日韩在线亚洲综合国产人 | 中文字幕无线码免费人妻 | 国产明星裸体无码xxxx视频 | 兔费看少妇性l交大片免费 | 小鲜肉自慰网站xnxx | 亚洲区欧美区综合区自拍区 | 久久久久久亚洲精品a片成人 | 欧美日本免费一区二区三区 | 国内揄拍国内精品少妇国语 | 久久国内精品自在自线 | 少妇的肉体aa片免费 | 久久综合久久自在自线精品自 | 无码人妻少妇伦在线电影 | 色欲人妻aaaaaaa无码 | 无码播放一区二区三区 | 东京热男人av天堂 | 国产精品va在线播放 | 久久久精品456亚洲影院 | 麻豆av传媒蜜桃天美传媒 | 无套内射视频囯产 | 野外少妇愉情中文字幕 | 中文字幕无码av激情不卡 | 亚洲欧美综合区丁香五月小说 | 国产精品无码永久免费888 | 中文亚洲成a人片在线观看 | 精品久久久久久人妻无码中文字幕 | 欧美人与善在线com | 国产精品亚洲а∨无码播放麻豆 | 亚洲a无码综合a国产av中文 | 亚洲精品一区二区三区婷婷月 | 一本大道久久东京热无码av | 国产精品亚洲一区二区三区喷水 | 日韩av无码一区二区三区 | 色婷婷欧美在线播放内射 | 丰满岳乱妇在线观看中字无码 | 性史性农村dvd毛片 | 亚洲一区二区三区香蕉 | 国产区女主播在线观看 | 亚洲精品欧美二区三区中文字幕 | 三级4级全黄60分钟 | 精品无码一区二区三区的天堂 | 成人免费视频视频在线观看 免费 | 色狠狠av一区二区三区 | 狠狠cao日日穞夜夜穞av | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 天干天干啦夜天干天2017 | 中文字幕无线码免费人妻 | 亚洲一区av无码专区在线观看 | ass日本丰满熟妇pics | 精品少妇爆乳无码av无码专区 | 日韩欧美中文字幕在线三区 | 亚洲中文字幕无码一久久区 | 久青草影院在线观看国产 | 久久熟妇人妻午夜寂寞影院 | 久9re热视频这里只有精品 | 国产综合在线观看 | 秋霞成人午夜鲁丝一区二区三区 | 国产熟妇高潮叫床视频播放 | 亚洲精品综合五月久久小说 | 成人aaa片一区国产精品 | 欧美日韩亚洲国产精品 | 国产亚洲欧美日韩亚洲中文色 | 精品成人av一区二区三区 | 国精产品一品二品国精品69xx | 欧美性猛交内射兽交老熟妇 | 色窝窝无码一区二区三区色欲 | 色综合久久中文娱乐网 | 丰满少妇熟乱xxxxx视频 | 中文字幕精品av一区二区五区 | 伊人久久大香线蕉午夜 | 精品久久久无码人妻字幂 | 国产黄在线观看免费观看不卡 | 99久久久无码国产aaa精品 | 男女超爽视频免费播放 | 亚洲国产精品毛片av不卡在线 | 日韩av无码一区二区三区 | 天下第一社区视频www日本 | 日本www一道久久久免费榴莲 | 少妇一晚三次一区二区三区 | 熟妇人妻中文av无码 | 亚洲欧洲中文日韩av乱码 | 人人爽人人澡人人人妻 | 国产精品香蕉在线观看 | 国产熟女一区二区三区四区五区 | 婷婷色婷婷开心五月四房播播 | 在线播放无码字幕亚洲 | 亚洲日韩精品欧美一区二区 | 中文字幕中文有码在线 | 国产极品美女高潮无套在线观看 | 黑人巨大精品欧美一区二区 | 亚洲成av人片天堂网无码】 | 国产亚洲人成在线播放 | 精品久久久久久亚洲精品 | 麻豆精品国产精华精华液好用吗 | 中文字幕无线码免费人妻 | 国产人妻精品午夜福利免费 | 人妻少妇精品无码专区动漫 | 人妻尝试又大又粗久久 | 中文毛片无遮挡高清免费 | 秋霞成人午夜鲁丝一区二区三区 | 偷窥日本少妇撒尿chinese | 亚洲呦女专区 | 成人免费视频一区二区 | 青青草原综合久久大伊人精品 | 强伦人妻一区二区三区视频18 | 麻豆果冻传媒2021精品传媒一区下载 | 日本熟妇浓毛 | 在线观看国产一区二区三区 | 正在播放老肥熟妇露脸 | 女高中生第一次破苞av | 欧洲欧美人成视频在线 | 日韩成人一区二区三区在线观看 | 亚洲精品久久久久久久久久久 | 小sao货水好多真紧h无码视频 | 牲欲强的熟妇农村老妇女视频 | 亚洲国产成人av在线观看 | 午夜男女很黄的视频 | 亚洲日本一区二区三区在线 | 欧美老人巨大xxxx做受 | 精品一区二区不卡无码av | av无码电影一区二区三区 | 欧美性黑人极品hd | 精品乱子伦一区二区三区 | 亚洲国产日韩a在线播放 | 免费观看的无遮挡av | 国产农村乱对白刺激视频 | 国产精品va在线播放 | 理论片87福利理论电影 | 国产精品人人爽人人做我的可爱 | 精品人妻av区 | 无人区乱码一区二区三区 | 免费人成在线视频无码 | 日本高清一区免费中文视频 | 99视频精品全部免费免费观看 | 国产精品丝袜黑色高跟鞋 | 国产成人无码午夜视频在线观看 | 无码吃奶揉捏奶头高潮视频 | 久久亚洲精品中文字幕无男同 | 国产激情精品一区二区三区 | 大地资源网第二页免费观看 | 夜夜夜高潮夜夜爽夜夜爰爰 | 伊在人天堂亚洲香蕉精品区 | 久久国内精品自在自线 | 国产三级精品三级男人的天堂 | 国产精品资源一区二区 | 伊人久久婷婷五月综合97色 | 久久久中文久久久无码 | 久久久久99精品国产片 | 国语精品一区二区三区 | 国产乱人偷精品人妻a片 | 欧美丰满老熟妇xxxxx性 | 色综合天天综合狠狠爱 | 76少妇精品导航 | 中文字幕精品av一区二区五区 | 亚洲国产精品无码久久久久高潮 | 国产亚洲精品久久久久久国模美 | 久9re热视频这里只有精品 | 亚洲精品鲁一鲁一区二区三区 | 玩弄人妻少妇500系列视频 | 亚洲色大成网站www国产 | 18无码粉嫩小泬无套在线观看 | 国产97在线 | 亚洲 | 色综合久久中文娱乐网 | 久久视频在线观看精品 | 日本一区二区三区免费高清 | 中文字幕乱妇无码av在线 | 日本熟妇乱子伦xxxx | 少妇激情av一区二区 | 欧美真人作爱免费视频 | 丰满肥臀大屁股熟妇激情视频 | 97精品人妻一区二区三区香蕉 | 亚洲爆乳精品无码一区二区三区 | 国产精品久久久久9999小说 | 亚洲精品综合五月久久小说 | 人人爽人人爽人人片av亚洲 | 亚洲中文字幕在线无码一区二区 | 国产人妻精品午夜福利免费 | 永久免费观看国产裸体美女 | 欧洲熟妇精品视频 | 亚洲小说春色综合另类 | 久在线观看福利视频 | 精品国产成人一区二区三区 | 国产综合久久久久鬼色 | 秋霞特色aa大片 | 免费视频欧美无人区码 | 国产熟女一区二区三区四区五区 | 99麻豆久久久国产精品免费 | 夜夜高潮次次欢爽av女 | 久久国产精品二国产精品 | 午夜时刻免费入口 | 精品久久综合1区2区3区激情 | 久久99热只有频精品8 | 欧美丰满少妇xxxx性 | aⅴ在线视频男人的天堂 | 动漫av一区二区在线观看 | 99视频精品全部免费免费观看 | 又色又爽又黄的美女裸体网站 | 疯狂三人交性欧美 | 骚片av蜜桃精品一区 | 亚洲男女内射在线播放 | 人妻aⅴ无码一区二区三区 | 国产在线无码精品电影网 | 国产成人无码av片在线观看不卡 | 初尝人妻少妇中文字幕 | 精品成人av一区二区三区 | 国产亚洲人成a在线v网站 | 亚洲s码欧洲m码国产av | 亚洲伊人久久精品影院 | 久久99热只有频精品8 | 波多野结衣aⅴ在线 | 小鲜肉自慰网站xnxx | √8天堂资源地址中文在线 | 一本色道婷婷久久欧美 | 蜜臀aⅴ国产精品久久久国产老师 | 中文字幕人妻无码一区二区三区 | 精品午夜福利在线观看 | 少妇无码吹潮 | 亚洲国产精品一区二区第一页 | 女人被男人躁得好爽免费视频 | 露脸叫床粗话东北少妇 | 东京一本一道一二三区 | 蜜臀av在线播放 久久综合激激的五月天 | 成人免费视频在线观看 | 无码任你躁久久久久久久 | 欧美兽交xxxx×视频 | 又大又紧又粉嫩18p少妇 | 欧美日韩人成综合在线播放 | 欧洲精品码一区二区三区免费看 | 久久亚洲日韩精品一区二区三区 | 亚洲日韩乱码中文无码蜜桃臀网站 | 精品无码一区二区三区爱欲 | 国产艳妇av在线观看果冻传媒 | 免费人成网站视频在线观看 | 99久久久国产精品无码免费 | 亚洲精品中文字幕乱码 | av在线亚洲欧洲日产一区二区 | 欧美老熟妇乱xxxxx | 人妻少妇精品无码专区动漫 | 荫蒂被男人添的好舒服爽免费视频 | 久久www免费人成人片 | 中国大陆精品视频xxxx | 偷窥村妇洗澡毛毛多 | 久久精品99久久香蕉国产色戒 | 国产农村妇女高潮大叫 | 久久综合狠狠综合久久综合88 | 日本乱偷人妻中文字幕 | 久久精品人妻少妇一区二区三区 | 精品久久久无码中文字幕 | 天堂а√在线地址中文在线 | 99在线 | 亚洲 | 2020久久香蕉国产线看观看 | 中文字幕av伊人av无码av | 狂野欧美性猛xxxx乱大交 | 鲁大师影院在线观看 | 亚洲日本在线电影 | 国产香蕉尹人视频在线 | 丰满少妇人妻久久久久久 | 小泽玛莉亚一区二区视频在线 | 理论片87福利理论电影 | 国产精品久久久av久久久 | a在线观看免费网站大全 | 色欲人妻aaaaaaa无码 | 久久99精品久久久久久动态图 | 精品成人av一区二区三区 | 精品人妻av区 | 国产真实伦对白全集 | 亚洲日韩精品欧美一区二区 | 性欧美熟妇videofreesex | 一区二区三区乱码在线 | 欧洲 | 中文字幕亚洲情99在线 | 六月丁香婷婷色狠狠久久 | 国产成人精品优优av | 国产精品久久久久7777 | 伊人久久大香线焦av综合影院 | 午夜无码区在线观看 | 国产成人无码av在线影院 | 免费国产黄网站在线观看 | 久精品国产欧美亚洲色aⅴ大片 | 无码人妻黑人中文字幕 | 国产三级精品三级男人的天堂 | 波多野结衣av一区二区全免费观看 | аⅴ资源天堂资源库在线 | 亚洲日韩av一区二区三区四区 | 九九在线中文字幕无码 | 丰满少妇人妻久久久久久 | 国产精品第一国产精品 | 亚洲日韩乱码中文无码蜜桃臀网站 | 久久久久久久久888 | 野狼第一精品社区 | 无码国模国产在线观看 | 国产乱人无码伦av在线a | 水蜜桃色314在线观看 | 日本www一道久久久免费榴莲 | 国产做国产爱免费视频 | 国产综合色产在线精品 | 国产亚洲tv在线观看 | 亚洲成熟女人毛毛耸耸多 | 中文字幕乱码中文乱码51精品 | 亚洲人成人无码网www国产 | 999久久久国产精品消防器材 | 日韩av无码一区二区三区不卡 | 国产凸凹视频一区二区 | 国产精品亚洲а∨无码播放麻豆 | 男人和女人高潮免费网站 | 亚洲熟悉妇女xxx妇女av | 性欧美牲交在线视频 | 久久综合香蕉国产蜜臀av | 国产精品-区区久久久狼 | 九九久久精品国产免费看小说 | 国内少妇偷人精品视频免费 | 精品成在人线av无码免费看 | 亚洲欧美色中文字幕在线 | 乱人伦人妻中文字幕无码 | 熟女俱乐部五十路六十路av | 亚洲精品综合一区二区三区在线 | 最新版天堂资源中文官网 | 国产激情无码一区二区 | 亚洲国产精品毛片av不卡在线 | 国产精品久久久久7777 | 精品欧洲av无码一区二区三区 | 四虎国产精品一区二区 | 无码人妻黑人中文字幕 | 国产精品久久久一区二区三区 | 天堂无码人妻精品一区二区三区 | 亚洲中文字幕在线无码一区二区 | 97精品人妻一区二区三区香蕉 | 亚洲国产精品一区二区第一页 | 日日夜夜撸啊撸 | а√资源新版在线天堂 | 青青久在线视频免费观看 | 久久 国产 尿 小便 嘘嘘 | 扒开双腿疯狂进出爽爽爽视频 | 大胆欧美熟妇xx | 日产国产精品亚洲系列 | 99精品视频在线观看免费 | 免费观看激色视频网站 | а天堂中文在线官网 | 色婷婷综合中文久久一本 | 国语自产偷拍精品视频偷 | 国产九九九九九九九a片 | 久久久久久久久蜜桃 | 成人无码影片精品久久久 | 三上悠亚人妻中文字幕在线 | 少妇性l交大片 | 国产av一区二区精品久久凹凸 | 波多野42部无码喷潮在线 | 暴力强奷在线播放无码 | 无遮挡国产高潮视频免费观看 | 妺妺窝人体色www在线小说 | 亚洲熟熟妇xxxx | 亚洲精品国偷拍自产在线麻豆 | 99久久精品无码一区二区毛片 | 精品人妻人人做人人爽 | 精品成人av一区二区三区 | 亚洲精品无码人妻无码 | а√天堂www在线天堂小说 | 亚洲精品无码国产 | 欧美真人作爱免费视频 | 欧美性猛交xxxx富婆 | 人人妻人人澡人人爽人人精品 | 日日干夜夜干 | 久青草影院在线观看国产 | 国产精品亚洲专区无码不卡 | 中文精品久久久久人妻不卡 | 国产熟妇高潮叫床视频播放 | 无码人妻精品一区二区三区下载 | 欧美激情一区二区三区成人 | 亚洲色无码一区二区三区 | 欧美 日韩 亚洲 在线 | 精品成人av一区二区三区 | 久久这里只有精品视频9 | 中文字幕无码日韩欧毛 | 精品日本一区二区三区在线观看 | 一本久久伊人热热精品中文字幕 | 日韩人妻少妇一区二区三区 | 日本饥渴人妻欲求不满 | 国产成人精品视频ⅴa片软件竹菊 | 欧美人与动性行为视频 | 美女黄网站人色视频免费国产 | 成在人线av无码免观看麻豆 | 亚洲高清偷拍一区二区三区 | 中文字幕无码av波多野吉衣 | 99久久无码一区人妻 | 亚洲欧美日韩综合久久久 | 东京无码熟妇人妻av在线网址 | 日韩av激情在线观看 | 色综合久久久久综合一本到桃花网 | 亚洲国产欧美日韩精品一区二区三区 | √8天堂资源地址中文在线 | 国产成人一区二区三区别 | 最新版天堂资源中文官网 | 欧美黑人巨大xxxxx | 人人爽人人澡人人人妻 | 在线看片无码永久免费视频 | 一本久道久久综合狠狠爱 | 国产亲子乱弄免费视频 | 正在播放老肥熟妇露脸 | 东京热无码av男人的天堂 | 岛国片人妻三上悠亚 | 日日橹狠狠爱欧美视频 | 亚洲 高清 成人 动漫 | 红桃av一区二区三区在线无码av | 中文字幕人妻无码一夲道 | 亚洲无人区一区二区三区 | 亚洲国产精品一区二区美利坚 | 网友自拍区视频精品 | 一区二区三区乱码在线 | 欧洲 | 国产乱人无码伦av在线a | 人人澡人摸人人添 | 真人与拘做受免费视频一 | 日韩欧美群交p片內射中文 | 久9re热视频这里只有精品 | 日本又色又爽又黄的a片18禁 | 一本久道久久综合婷婷五月 | ass日本丰满熟妇pics | 真人与拘做受免费视频一 | 成在人线av无码免观看麻豆 | 人人澡人人妻人人爽人人蜜桃 | 午夜丰满少妇性开放视频 | 国产亚洲精品久久久ai换 | 亚洲天堂2017无码中文 | 国精产品一品二品国精品69xx | 乌克兰少妇xxxx做受 | 人妻无码αv中文字幕久久琪琪布 | 女人和拘做爰正片视频 | 成熟妇人a片免费看网站 | 水蜜桃色314在线观看 | 青草青草久热国产精品 | 成人免费无码大片a毛片 | 亚洲 另类 在线 欧美 制服 | 国产精品办公室沙发 | 大肉大捧一进一出视频出来呀 | 日本一本二本三区免费 | 精品无码一区二区三区爱欲 | 日产国产精品亚洲系列 | 欧美黑人乱大交 | 人妻aⅴ无码一区二区三区 | 1000部夫妻午夜免费 | 在线欧美精品一区二区三区 | 亲嘴扒胸摸屁股激烈网站 | 日韩av无码一区二区三区不卡 | 亚洲综合色区中文字幕 | 久久久久国色av免费观看性色 | 两性色午夜视频免费播放 | 久久久无码中文字幕久... | 亚洲国产精品毛片av不卡在线 | 俺去俺来也在线www色官网 | 国产特级毛片aaaaaaa高清 | 无码人妻丰满熟妇区五十路百度 | 四虎永久在线精品免费网址 | 国产人妻精品一区二区三区 | 亚洲天堂2017无码中文 | 久久精品国产日本波多野结衣 | 国产亚洲精品精品国产亚洲综合 | 波多野结衣一区二区三区av免费 | 亚洲狠狠色丁香婷婷综合 | 男人和女人高潮免费网站 | 国产精品久久国产三级国 | 久久久久久国产精品无码下载 | 国产精品va在线观看无码 | 亚洲 a v无 码免 费 成 人 a v | 国产又爽又黄又刺激的视频 | 国产黄在线观看免费观看不卡 | 久久99热只有频精品8 | 性生交大片免费看女人按摩摩 | 亚洲国产欧美在线成人 | 欧美性猛交内射兽交老熟妇 | 乱人伦人妻中文字幕无码久久网 | 日日夜夜撸啊撸 | 久久精品女人的天堂av | 久久午夜无码鲁丝片秋霞 | 中文字幕 人妻熟女 | 欧美丰满熟妇xxxx性ppx人交 | 精品人妻人人做人人爽夜夜爽 | 丰满诱人的人妻3 | 亚洲自偷精品视频自拍 | 福利一区二区三区视频在线观看 | 亚洲の无码国产の无码影院 | 国产成人无码一二三区视频 | 亚洲经典千人经典日产 | 人人爽人人澡人人高潮 | 乌克兰少妇xxxx做受 | 爽爽影院免费观看 | 久久午夜无码鲁丝片 | 日日鲁鲁鲁夜夜爽爽狠狠 | 亚洲精品一区二区三区在线观看 | 色爱情人网站 | 国产成人无码午夜视频在线观看 | 装睡被陌生人摸出水好爽 | 激情综合激情五月俺也去 | 久久久久免费精品国产 | 奇米影视7777久久精品 | 亚洲精品久久久久久久久久久 | 中文字幕人成乱码熟女app | 鲁大师影院在线观看 | 性生交大片免费看女人按摩摩 | 国产绳艺sm调教室论坛 | av无码久久久久不卡免费网站 | 午夜福利电影 | 亚洲高清偷拍一区二区三区 | 久久99久久99精品中文字幕 | 精品国精品国产自在久国产87 | 免费看男女做好爽好硬视频 | 成人无码精品1区2区3区免费看 | 欧美日韩人成综合在线播放 | 久久97精品久久久久久久不卡 | 亚洲一区二区三区播放 | 欧美xxxx黑人又粗又长 | 亚洲精品一区二区三区四区五区 | 无码人妻丰满熟妇区五十路百度 | 国产欧美精品一区二区三区 | 亚洲成av人片在线观看无码不卡 | 国产成人无码a区在线观看视频app | 日韩视频 中文字幕 视频一区 | 亚洲日韩一区二区 | 国产精华av午夜在线观看 | 亚洲日韩av一区二区三区四区 | 夫妻免费无码v看片 | 岛国片人妻三上悠亚 | 国产成人无码区免费内射一片色欲 | 亚洲精品一区二区三区四区五区 | 色婷婷欧美在线播放内射 | 亚洲欧美色中文字幕在线 | 红桃av一区二区三区在线无码av | 久久久精品国产sm最大网站 | 无遮无挡爽爽免费视频 | 亚洲精品中文字幕 | 中文字幕乱码人妻二区三区 | 亚洲中文字幕无码中字 | 97久久国产亚洲精品超碰热 | 国产人妻人伦精品 | 亚洲精品久久久久久久久久久 | 福利一区二区三区视频在线观看 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 88国产精品欧美一区二区三区 | 天堂а√在线地址中文在线 | 日韩欧美群交p片內射中文 | 精品一区二区三区波多野结衣 | 国产真实夫妇视频 | 人妻少妇精品无码专区动漫 | 国产情侣作爱视频免费观看 | 欧美日韩一区二区综合 | 精品久久久无码人妻字幂 | 亚洲国产精品美女久久久久 | 丰满少妇弄高潮了www | 欧美成人午夜精品久久久 | 亚洲一区二区三区无码久久 | 中文字幕无码av波多野吉衣 | 一个人看的视频www在线 | а√天堂www在线天堂小说 | 狠狠色欧美亚洲狠狠色www | 四虎影视成人永久免费观看视频 | 成人试看120秒体验区 | 欧美日韩在线亚洲综合国产人 | 国产精品对白交换视频 | 亚洲综合色区中文字幕 | 日韩av无码一区二区三区 | 性欧美熟妇videofreesex | 国产一区二区三区影院 | 网友自拍区视频精品 | 中文字幕乱码中文乱码51精品 | 久精品国产欧美亚洲色aⅴ大片 | 久久亚洲a片com人成 | 丰满岳乱妇在线观看中字无码 | 东京热一精品无码av | 亚洲精品久久久久久一区二区 | 无码精品国产va在线观看dvd | 青青久在线视频免费观看 | 波多野结衣av在线观看 | 婷婷五月综合激情中文字幕 | 人妻少妇精品无码专区动漫 | 亚洲精品午夜国产va久久成人 | 熟妇人妻无乱码中文字幕 | av在线亚洲欧洲日产一区二区 | 亚洲熟女一区二区三区 | 鲁一鲁av2019在线 | 99久久99久久免费精品蜜桃 | 无码国产色欲xxxxx视频 | av香港经典三级级 在线 | 老司机亚洲精品影院无码 | 精品少妇爆乳无码av无码专区 | 久久婷婷五月综合色国产香蕉 | 青草青草久热国产精品 | 久久www免费人成人片 | 国产精品成人av在线观看 | 亚洲国产精品一区二区第一页 | 伊人久久婷婷五月综合97色 | 亚洲国产成人a精品不卡在线 | 少妇久久久久久人妻无码 | 久青草影院在线观看国产 | 青青青爽视频在线观看 | 黑人巨大精品欧美黑寡妇 | 日韩视频 中文字幕 视频一区 | 人人妻人人澡人人爽欧美精品 | 成人综合网亚洲伊人 | 久久久久久久人妻无码中文字幕爆 | 国产香蕉尹人综合在线观看 | 中文无码伦av中文字幕 | 亚洲国产精品一区二区美利坚 | 日韩在线不卡免费视频一区 | 亚洲第一网站男人都懂 | 永久黄网站色视频免费直播 | 国内精品九九久久久精品 | 亲嘴扒胸摸屁股激烈网站 | 亚洲日本一区二区三区在线 | 伊人久久大香线蕉午夜 | 高潮毛片无遮挡高清免费视频 | 纯爱无遮挡h肉动漫在线播放 | 国产精品自产拍在线观看 | 国内揄拍国内精品人妻 | 4hu四虎永久在线观看 | 天下第一社区视频www日本 | 亚洲自偷自拍另类第1页 | 久久久精品成人免费观看 | 青青草原综合久久大伊人精品 | 青青久在线视频免费观看 | 永久免费精品精品永久-夜色 | 成熟女人特级毛片www免费 | 亚洲春色在线视频 | 领导边摸边吃奶边做爽在线观看 | 色情久久久av熟女人妻网站 | 成人亚洲精品久久久久 | 成人精品天堂一区二区三区 | 中文字幕无码免费久久99 | 久久精品人人做人人综合 | 伊人久久大香线焦av综合影院 | 国内少妇偷人精品视频 | 成 人影片 免费观看 | 99精品无人区乱码1区2区3区 | 麻豆国产丝袜白领秘书在线观看 | 精品国产一区二区三区四区 | 亚洲人成影院在线无码按摩店 | www国产精品内射老师 | 欧美高清在线精品一区 | 国产两女互慰高潮视频在线观看 | 日产精品高潮呻吟av久久 | 波多野结衣高清一区二区三区 | 日本精品人妻无码77777 天堂一区人妻无码 | 成人欧美一区二区三区黑人免费 | 国产在热线精品视频 | 国产成人无码av片在线观看不卡 | 亚洲日本va中文字幕 | 强伦人妻一区二区三区视频18 | 天天摸天天碰天天添 | 国产三级久久久精品麻豆三级 | 亚洲国产精品久久久久久 | 久久精品国产精品国产精品污 | 日本大香伊一区二区三区 | 亚洲色在线无码国产精品不卡 | 男女作爱免费网站 | 少妇高潮喷潮久久久影院 | 国产亚洲精品久久久久久国模美 | 无遮挡国产高潮视频免费观看 | 免费观看的无遮挡av | 日本精品人妻无码77777 天堂一区人妻无码 | 国产亚洲视频中文字幕97精品 | 波多野结衣高清一区二区三区 | 久久综合久久自在自线精品自 | 久久综合九色综合97网 | 人妻熟女一区 | 99久久婷婷国产综合精品青草免费 | 丁香花在线影院观看在线播放 | 久久久婷婷五月亚洲97号色 | 欧美日韩视频无码一区二区三 | 亚洲国产精品久久人人爱 | 麻豆国产97在线 | 欧洲 | 中文字幕无码av波多野吉衣 | 精品久久久久久亚洲精品 | 丝袜 中出 制服 人妻 美腿 | 无码人妻丰满熟妇区五十路百度 | 精品无码av一区二区三区 | 亚洲熟妇色xxxxx欧美老妇y | 九九综合va免费看 | 亚洲中文字幕无码中文字在线 | 狠狠色欧美亚洲狠狠色www | 日本一区二区三区免费高清 | 国产精品自产拍在线观看 | 曰韩少妇内射免费播放 | 97久久超碰中文字幕 | 亚洲а∨天堂久久精品2021 | 日本一区二区三区免费播放 | 久久国产劲爆∧v内射 | 国产成人亚洲综合无码 | 国产婷婷色一区二区三区在线 | 精品熟女少妇av免费观看 | 欧美精品免费观看二区 | 色婷婷香蕉在线一区二区 | 亚洲欧美中文字幕5发布 | 麻豆av传媒蜜桃天美传媒 | 久久精品国产一区二区三区肥胖 | 99久久99久久免费精品蜜桃 | 久久无码人妻影院 | 在线播放亚洲第一字幕 | 国产成人无码专区 | 国产精品无码成人午夜电影 | 久久精品中文字幕一区 | 无码av中文字幕免费放 | 日韩人妻系列无码专区 | 国产亚洲精品精品国产亚洲综合 | 国产精品久久久av久久久 | 国产精品亚洲五月天高清 | 一本色道久久综合亚洲精品不卡 | 十八禁视频网站在线观看 | 西西人体www44rt大胆高清 | 综合激情五月综合激情五月激情1 | 性色欲网站人妻丰满中文久久不卡 | a片免费视频在线观看 | 婷婷丁香六月激情综合啪 | 永久免费精品精品永久-夜色 | 久久综合激激的五月天 | 久久国语露脸国产精品电影 | 亚洲一区二区三区 | 精品亚洲成av人在线观看 | 中文字幕日产无线码一区 | 国产亚洲精品久久久久久久 | 国产精品久久精品三级 | 狠狠躁日日躁夜夜躁2020 | 国产一精品一av一免费 | 久久www免费人成人片 | 麻豆成人精品国产免费 | 成人性做爰aaa片免费看不忠 | www国产亚洲精品久久网站 | 日日碰狠狠丁香久燥 | 人妻无码久久精品人妻 | 亚洲第一无码av无码专区 | 欧美黑人巨大xxxxx | 日日天日日夜日日摸 | 国产真人无遮挡作爱免费视频 | a在线亚洲男人的天堂 | 久久精品国产一区二区三区肥胖 | √8天堂资源地址中文在线 | 国产人妻人伦精品 | 一个人看的www免费视频在线观看 | 国产成人无码av一区二区 | 国产精品无码永久免费888 | 日本饥渴人妻欲求不满 | 亚洲色大成网站www国产 | 亚洲精品久久久久久一区二区 | 性生交片免费无码看人 | 亚洲成色在线综合网站 | 人人澡人人妻人人爽人人蜜桃 | 精品乱码久久久久久久 | 日日摸夜夜摸狠狠摸婷婷 | 中文字幕av伊人av无码av | 美女黄网站人色视频免费国产 | 美女黄网站人色视频免费国产 | 精品无码一区二区三区爱欲 | 影音先锋中文字幕无码 | 国产97人人超碰caoprom | 国产亚洲精品久久久久久国模美 | 色婷婷久久一区二区三区麻豆 | 精品久久久无码中文字幕 | 久久亚洲精品成人无码 | 亚洲s码欧洲m码国产av | 欧美激情一区二区三区成人 | 日本熟妇人妻xxxxx人hd | 真人与拘做受免费视频 | 成人毛片一区二区 | 18黄暴禁片在线观看 | 国产人妻人伦精品1国产丝袜 | 成熟人妻av无码专区 | 国産精品久久久久久久 | 中文无码精品a∨在线观看不卡 | 图片小说视频一区二区 | 日本大乳高潮视频在线观看 | 老司机亚洲精品影院无码 | 中国大陆精品视频xxxx | 国产成人一区二区三区别 | 久久人人爽人人爽人人片av高清 | 欧美 日韩 亚洲 在线 | 国产卡一卡二卡三 | 天天拍夜夜添久久精品大 | 在线精品亚洲一区二区 | 强辱丰满人妻hd中文字幕 | 欧美性猛交内射兽交老熟妇 | 丰满少妇女裸体bbw | 国产猛烈高潮尖叫视频免费 | 久久99精品久久久久久 | 日韩无码专区 | 欧美怡红院免费全部视频 | 领导边摸边吃奶边做爽在线观看 | 精品无码av一区二区三区 | 亚洲一区二区三区在线观看网站 | 精品人妻人人做人人爽 | 久久久精品成人免费观看 | 国产香蕉尹人视频在线 | 人妻与老人中文字幕 | 骚片av蜜桃精品一区 | 九一九色国产 | 麻豆国产人妻欲求不满谁演的 | 国产舌乚八伦偷品w中 | 亚洲乱亚洲乱妇50p | 久久精品无码一区二区三区 | 欧美猛少妇色xxxxx | 成人女人看片免费视频放人 | 久久久国产一区二区三区 | 亚洲 日韩 欧美 成人 在线观看 | 丁香啪啪综合成人亚洲 | 波多野结衣av在线观看 | 人妻夜夜爽天天爽三区 | 久久无码人妻影院 | 成人亚洲精品久久久久 | 日韩无套无码精品 | 男人扒开女人内裤强吻桶进去 | 国产人妻精品一区二区三区 | 久久99精品久久久久久动态图 | 无码人妻出轨黑人中文字幕 | 97无码免费人妻超级碰碰夜夜 | 久激情内射婷内射蜜桃人妖 | 亚洲一区二区三区国产精华液 | 无码人妻精品一区二区三区下载 | 青青青爽视频在线观看 | 国产精品久久精品三级 | 野狼第一精品社区 | 在线看片无码永久免费视频 | 亚洲第一无码av无码专区 | 亚洲精品中文字幕乱码 | 国产麻豆精品一区二区三区v视界 | 麻豆人妻少妇精品无码专区 | 日日摸天天摸爽爽狠狠97 | 麻豆精产国品 | 无遮挡国产高潮视频免费观看 | 麻豆精产国品 | 国产熟女一区二区三区四区五区 | 成人免费视频视频在线观看 免费 | 18黄暴禁片在线观看 | 老司机亚洲精品影院无码 | 婷婷丁香六月激情综合啪 | 美女毛片一区二区三区四区 | 亚洲综合伊人久久大杳蕉 | 亚洲中文字幕久久无码 | 久久99精品久久久久婷婷 | 国产精品美女久久久久av爽李琼 | 国产97人人超碰caoprom | 影音先锋中文字幕无码 | 国产精品无码一区二区三区不卡 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产精品久久久一区二区三区 | 精品无码一区二区三区的天堂 | 欧美日韩综合一区二区三区 | 久久久成人毛片无码 | 久久午夜无码鲁丝片午夜精品 | 九月婷婷人人澡人人添人人爽 | 99久久精品无码一区二区毛片 | 精品国产一区二区三区四区在线看 | 日韩人妻少妇一区二区三区 | 欧美放荡的少妇 | 性欧美大战久久久久久久 | 97精品人妻一区二区三区香蕉 | 国产又爽又猛又粗的视频a片 | 最新国产麻豆aⅴ精品无码 | 国产两女互慰高潮视频在线观看 | 四虎影视成人永久免费观看视频 | 欧美一区二区三区视频在线观看 | 亚洲一区二区三区香蕉 | 亚洲s色大片在线观看 | 国产色视频一区二区三区 | 久久熟妇人妻午夜寂寞影院 | 亚洲成av人片天堂网无码】 | 夜夜高潮次次欢爽av女 | 亚洲 日韩 欧美 成人 在线观看 | 2019nv天堂香蕉在线观看 | 亚洲综合无码久久精品综合 | 中文字幕av日韩精品一区二区 | 欧美人与禽zoz0性伦交 | 亚洲日韩av一区二区三区中文 | 国产真人无遮挡作爱免费视频 | 国内少妇偷人精品视频 | 色综合视频一区二区三区 | 国产黄在线观看免费观看不卡 | 无码av中文字幕免费放 | 激情五月综合色婷婷一区二区 | 丰腴饱满的极品熟妇 | 久久精品国产一区二区三区肥胖 | 九月婷婷人人澡人人添人人爽 | 精品一区二区三区波多野结衣 | 欧美老妇交乱视频在线观看 | 国产精品人人爽人人做我的可爱 | 国内精品人妻无码久久久影院蜜桃 | 无码纯肉视频在线观看 | 亚洲小说春色综合另类 | 欧美熟妇另类久久久久久多毛 | 日韩av激情在线观看 | 人人妻人人澡人人爽人人精品 | 国产一区二区三区精品视频 | 三上悠亚人妻中文字幕在线 | 桃花色综合影院 | 水蜜桃亚洲一二三四在线 | 国产在线精品一区二区三区直播 | 国产精品18久久久久久麻辣 | 网友自拍区视频精品 | 天天躁夜夜躁狠狠是什么心态 | 久久精品女人天堂av免费观看 | 日本熟妇乱子伦xxxx | 色欲av亚洲一区无码少妇 | 久久精品国产亚洲精品 | 成人免费视频一区二区 | 水蜜桃色314在线观看 | 未满小14洗澡无码视频网站 | 一区二区传媒有限公司 | 骚片av蜜桃精品一区 | 宝宝好涨水快流出来免费视频 | 日韩av无码一区二区三区不卡 | 久久久久久a亚洲欧洲av冫 | 精品国精品国产自在久国产87 | 亚洲第一网站男人都懂 | 人人妻人人澡人人爽欧美一区 | 麻花豆传媒剧国产免费mv在线 | 精品久久久中文字幕人妻 | 亚洲狠狠婷婷综合久久 | 亚洲理论电影在线观看 | 高潮毛片无遮挡高清免费视频 | 大乳丰满人妻中文字幕日本 | 亚洲自偷自拍另类第1页 | 少妇一晚三次一区二区三区 | 天海翼激烈高潮到腰振不止 | 久久精品国产日本波多野结衣 | 丰满人妻精品国产99aⅴ | 亚洲国产午夜精品理论片 | 天天爽夜夜爽夜夜爽 | 性色欲网站人妻丰满中文久久不卡 | 中文字幕乱码人妻无码久久 | 国内精品人妻无码久久久影院 | 国产亚洲精品久久久久久国模美 | 最近免费中文字幕中文高清百度 | 日本va欧美va欧美va精品 | 国产精品内射视频免费 | 亚洲一区二区三区四区 | 丰满护士巨好爽好大乳 | 日韩亚洲欧美中文高清在线 | 亚洲国产精品久久久久久 | 少妇邻居内射在线 | 国产精品香蕉在线观看 | 日日摸天天摸爽爽狠狠97 | 亚洲精品www久久久 | 男女猛烈xx00免费视频试看 | 欧美国产日产一区二区 | 中文字幕无码免费久久9一区9 | 中文字幕无码乱人伦 | 日产精品99久久久久久 | 亚洲精品中文字幕乱码 | 免费人成在线视频无码 | 午夜精品一区二区三区的区别 | 亚洲一区二区三区偷拍女厕 | 亚洲精品鲁一鲁一区二区三区 | 日本护士xxxxhd少妇 | 97久久超碰中文字幕 | 97精品人妻一区二区三区香蕉 | 牲欲强的熟妇农村老妇女 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 曰韩无码二三区中文字幕 | 亚洲欧美精品aaaaaa片 | 未满成年国产在线观看 | 波多野结衣av一区二区全免费观看 | 国产又爽又黄又刺激的视频 | 亚洲自偷自拍另类第1页 | 小sao货水好多真紧h无码视频 | 波多野结衣一区二区三区av免费 | 久久人人爽人人爽人人片ⅴ | 久久伊人色av天堂九九小黄鸭 | 亚洲欧洲日本综合aⅴ在线 | 亚洲一区av无码专区在线观看 | 久久久www成人免费毛片 | 国产精品-区区久久久狼 | 最新版天堂资源中文官网 | 国产午夜亚洲精品不卡下载 | 成熟人妻av无码专区 | 丰满人妻一区二区三区免费视频 | 日日橹狠狠爱欧美视频 | 99在线 | 亚洲 | 男人扒开女人内裤强吻桶进去 | 国产在线aaa片一区二区99 | 女人高潮内射99精品 | 天堂一区人妻无码 | 极品嫩模高潮叫床 | 蜜桃臀无码内射一区二区三区 | 亚洲天堂2017无码中文 | 亚洲高清偷拍一区二区三区 | 伊人久久大香线焦av综合影院 | 少妇性l交大片 | 午夜无码区在线观看 | 一本精品99久久精品77 | 国内少妇偷人精品视频免费 | 精品水蜜桃久久久久久久 | 熟妇人妻中文av无码 | 少妇无套内谢久久久久 | 婷婷综合久久中文字幕蜜桃三电影 | 久久精品中文字幕大胸 | 窝窝午夜理论片影院 | 亚洲毛片av日韩av无码 | 国产精品久久久久影院嫩草 | 九九综合va免费看 | 国产乱人伦av在线无码 | 蜜臀aⅴ国产精品久久久国产老师 | 一区二区三区乱码在线 | 欧洲 | 中文字幕人成乱码熟女app | 蜜臀aⅴ国产精品久久久国产老师 | 亚洲国产精品毛片av不卡在线 | 国产亚洲精品久久久闺蜜 | 国产偷自视频区视频 | 国产麻豆精品一区二区三区v视界 | 国产精品亚洲五月天高清 | 国产成人精品久久亚洲高清不卡 | 人妻少妇精品视频专区 | 国产色视频一区二区三区 | 成人片黄网站色大片免费观看 | 欧美老妇交乱视频在线观看 | 日韩av无码中文无码电影 | 中文字幕日韩精品一区二区三区 | 亚洲理论电影在线观看 | 男人扒开女人内裤强吻桶进去 | 日日碰狠狠丁香久燥 | 无码av最新清无码专区吞精 | 日本精品人妻无码免费大全 | 国内揄拍国内精品少妇国语 | 亚洲爆乳大丰满无码专区 | 亚洲欧美日韩综合久久久 | 国产精品无套呻吟在线 | 丝袜 中出 制服 人妻 美腿 | 国产精品国产自线拍免费软件 | 久久综合久久自在自线精品自 | 亚洲成熟女人毛毛耸耸多 | 国产亚洲精品久久久久久久久动漫 | 亚洲乱亚洲乱妇50p | 99久久精品午夜一区二区 | 色婷婷香蕉在线一区二区 | 亚洲精品国产精品乱码视色 | 国产午夜无码视频在线观看 | 老子影院午夜伦不卡 | 亚洲成a人片在线观看无码3d | 牲交欧美兽交欧美 | 欧美日韩一区二区免费视频 | √天堂资源地址中文在线 | 少妇人妻偷人精品无码视频 | 一个人看的视频www在线 | 国产又爽又黄又刺激的视频 | 国产69精品久久久久app下载 | 精品国产一区av天美传媒 | 大肉大捧一进一出视频出来呀 | 亚洲第一网站男人都懂 | 99麻豆久久久国产精品免费 | 国模大胆一区二区三区 | 午夜精品久久久内射近拍高清 | 精品人妻人人做人人爽 | 婷婷五月综合缴情在线视频 | 中文字幕无码av激情不卡 | 亚洲精品久久久久avwww潮水 | 国产无遮挡又黄又爽免费视频 | 亚洲va欧美va天堂v国产综合 | 亚洲成色www久久网站 | 99er热精品视频 | 日韩av无码中文无码电影 | 国产无套粉嫩白浆在线 | 久久久久国色av免费观看性色 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 亚洲精品久久久久久一区二区 | 国产黄在线观看免费观看不卡 | 国产偷国产偷精品高清尤物 | 久久亚洲中文字幕精品一区 | 天堂а√在线地址中文在线 | 性欧美大战久久久久久久 | 国产免费久久精品国产传媒 | 国产精品香蕉在线观看 | 青春草在线视频免费观看 | 无遮挡国产高潮视频免费观看 | 欧美国产亚洲日韩在线二区 | 偷窥日本少妇撒尿chinese | 亚洲中文无码av永久不收费 | 国产精品自产拍在线观看 | 欧美日韩一区二区三区自拍 | 欧美高清在线精品一区 | 一本久道久久综合狠狠爱 | 国产97人人超碰caoprom | 无码吃奶揉捏奶头高潮视频 | 亚洲精品国产品国语在线观看 | 久久久久久久女国产乱让韩 | 天天躁夜夜躁狠狠是什么心态 | 天堂а√在线中文在线 | 日本乱偷人妻中文字幕 | 粗大的内捧猛烈进出视频 | 蜜桃视频韩日免费播放 | 亚洲国产日韩a在线播放 | 少妇激情av一区二区 | 中文字幕精品av一区二区五区 | 中文字幕无码av波多野吉衣 | 欧美精品国产综合久久 | 亚洲精品国产精品乱码不卡 | 久久精品99久久香蕉国产色戒 | av无码久久久久不卡免费网站 | 国产精品久久久久久亚洲毛片 | 日本熟妇人妻xxxxx人hd | 熟女少妇在线视频播放 | 樱花草在线播放免费中文 | 成年美女黄网站色大免费全看 | 精品欧洲av无码一区二区三区 | 中国女人内谢69xxxx | 99精品国产综合久久久久五月天 | 国产超级va在线观看视频 | 久久亚洲日韩精品一区二区三区 | 亚洲s码欧洲m码国产av | 国产av剧情md精品麻豆 | 精品午夜福利在线观看 | 国产亚洲精品久久久闺蜜 | 蜜桃无码一区二区三区 | 精品厕所偷拍各类美女tp嘘嘘 | 久久久久亚洲精品中文字幕 | 亚洲熟妇色xxxxx亚洲 | 国产色精品久久人妻 | 中文字幕日韩精品一区二区三区 | 丁香花在线影院观看在线播放 | 中文字幕无码免费久久9一区9 | 秋霞成人午夜鲁丝一区二区三区 | 日韩少妇内射免费播放 | 亚洲人成网站在线播放942 | 欧美xxxxx精品 | 亚洲高清偷拍一区二区三区 | 久久久久亚洲精品男人的天堂 | 国产女主播喷水视频在线观看 | 国产午夜精品一区二区三区嫩草 | 乱码av麻豆丝袜熟女系列 | 国产精品久久久久久亚洲影视内衣 | 又色又爽又黄的美女裸体网站 | 人人爽人人澡人人高潮 | 亚洲另类伦春色综合小说 | 国产午夜精品一区二区三区嫩草 | 天堂无码人妻精品一区二区三区 | 黑森林福利视频导航 | 狠狠躁日日躁夜夜躁2020 | 综合激情五月综合激情五月激情1 | 又湿又紧又大又爽a视频国产 | 麻豆蜜桃av蜜臀av色欲av | 国产亚洲精品久久久久久久 | 4hu四虎永久在线观看 | 久久久www成人免费毛片 | 久久久久亚洲精品中文字幕 | 成人av无码一区二区三区 | 捆绑白丝粉色jk震动捧喷白浆 | 亚洲成a人片在线观看无码 | 色偷偷人人澡人人爽人人模 | 少妇无套内谢久久久久 | 精品国产青草久久久久福利 | 九九综合va免费看 | 999久久久国产精品消防器材 | 久久精品中文字幕一区 | 色偷偷人人澡人人爽人人模 |